diff options
author | Pierre Ossman <ossman@cendio.se> | 2022-09-10 13:48:53 +0200 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2023-02-01 21:15:36 +0100 |
commit | baca73d03217a1c219d9c4f024ffcd39f85fd322 (patch) | |
tree | 0220df8a75d80575157701be539c48b47ef2fb6a /common | |
parent | bf0fb9129d397f7bbb27ba784890cd9c2102d839 (diff) | |
download | tigervnc-baca73d03217a1c219d9c4f024ffcd39f85fd322.tar.gz tigervnc-baca73d03217a1c219d9c4f024ffcd39f85fd322.zip |
Use templates for optimized code
Avoid preprocessor magic and instead rely on templating to generate
optimized functions for performance critical code.
Diffstat (limited to 'common')
31 files changed, 1582 insertions, 2062 deletions
diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 6a78939e..0fd070e8 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2014-2018 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * Copyright 2018 Peter Astrand for Cendio AB * * This is free software; you can redistribute it and/or modify @@ -1065,14 +1065,78 @@ rdr::U8* EncodeManager::OffsetPixelBuffer::getBufferRW(const Rect& /*r*/, int* / throw rfb::Exception("Invalid write attempt to OffsetPixelBuffer"); } -// Preprocessor generated, optimised methods - -#define BPP 8 -#include "EncodeManagerBPP.cxx" -#undef BPP -#define BPP 16 -#include "EncodeManagerBPP.cxx" -#undef BPP -#define BPP 32 -#include "EncodeManagerBPP.cxx" -#undef BPP +template<class T> +inline bool EncodeManager::checkSolidTile(const Rect& r, + const T colourValue, + const PixelBuffer *pb) +{ + int w, h; + const T* buffer; + int stride, pad; + + w = r.width(); + h = r.height(); + + buffer = (const T*)pb->getBuffer(r, &stride); + pad = stride - w; + + while (h--) { + int w_ = w; + while (w_--) { + if (*buffer != colourValue) + return false; + buffer++; + } + buffer += pad; + } + + return true; +} + +template<class T> +inline bool EncodeManager::analyseRect(int width, int height, + const T* buffer, int stride, + struct RectInfo *info, int maxColours) +{ + int pad; + + T colour; + int count; + + info->rleRuns = 0; + info->palette.clear(); + + pad = stride - width; + + // For efficiency, we only update the palette on changes in colour + colour = buffer[0]; + count = 0; + while (height--) { + int w_ = width; + while (w_--) { + if (*buffer != colour) { + if (!info->palette.insert(colour, count)) + return false; + if (info->palette.size() > maxColours) + return false; + + // FIXME: This doesn't account for switching lines + info->rleRuns++; + + colour = *buffer; + count = 0; + } + buffer++; + count++; + } + buffer += pad; + } + + // Make sure the final pixels also get counted + if (!info->palette.insert(colour, count)) + return false; + if (info->palette.size() > maxColours) + return false; + + return true; +} diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h index f8201c34..fc2b97d2 100644 --- a/common/rfb/EncodeManager.h +++ b/common/rfb/EncodeManager.h @@ -1,6 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2014-2018 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -97,22 +97,13 @@ namespace rfb { struct RectInfo *info, int maxColours); protected: - // Preprocessor generated, optimised methods - inline bool checkSolidTile(const Rect& r, rdr::U8 colourValue, + // Templated, optimised methods + template<class T> + inline bool checkSolidTile(const Rect& r, const T, const PixelBuffer *pb); - inline bool checkSolidTile(const Rect& r, rdr::U16 colourValue, - const PixelBuffer *pb); - inline bool checkSolidTile(const Rect& r, rdr::U32 colourValue, - const PixelBuffer *pb); - - inline bool analyseRect(int width, int height, - const rdr::U8* buffer, int stride, - struct RectInfo *info, int maxColours); - inline bool analyseRect(int width, int height, - const rdr::U16* buffer, int stride, - struct RectInfo *info, int maxColours); + template<class T> inline bool analyseRect(int width, int height, - const rdr::U32* buffer, int stride, + const T* buffer, int stride, struct RectInfo *info, int maxColours); protected: diff --git a/common/rfb/EncodeManagerBPP.cxx b/common/rfb/EncodeManagerBPP.cxx deleted file mode 100644 index 03612914..00000000 --- a/common/rfb/EncodeManagerBPP.cxx +++ /dev/null @@ -1,98 +0,0 @@ -/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. - * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) - -#define UBPP CONCAT2E(U,BPP) - -inline bool EncodeManager::checkSolidTile(const Rect& r, - rdr::UBPP colourValue, - const PixelBuffer *pb) -{ - int w, h; - const rdr::UBPP* buffer; - int stride, pad; - - w = r.width(); - h = r.height(); - - buffer = (const rdr::UBPP*)pb->getBuffer(r, &stride); - pad = stride - w; - - while (h--) { - int w_ = w; - while (w_--) { - if (*buffer != colourValue) - return false; - buffer++; - } - buffer += pad; - } - - return true; -} - -inline bool EncodeManager::analyseRect(int width, int height, - const rdr::UBPP* buffer, int stride, - struct RectInfo *info, int maxColours) -{ - int pad; - - rdr::UBPP colour; - int count; - - info->rleRuns = 0; - info->palette.clear(); - - pad = stride - width; - - // For efficiency, we only update the palette on changes in colour - colour = buffer[0]; - count = 0; - while (height--) { - int w_ = width; - while (w_--) { - if (*buffer != colour) { - if (!info->palette.insert(colour, count)) - return false; - if (info->palette.size() > maxColours) - return false; - - // FIXME: This doesn't account for switching lines - info->rleRuns++; - - colour = *buffer; - count = 0; - } - buffer++; - count++; - } - buffer += pad; - } - - // Make sure the final pixels also get counted - if (!info->palette.insert(colour, count)) - return false; - if (info->palette.size() > maxColours) - return false; - - return true; -} diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx index 73655da0..4275a049 100644 --- a/common/rfb/HextileDecoder.cxx +++ b/common/rfb/HextileDecoder.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,22 +25,14 @@ #include <rdr/MemInStream.h> #include <rdr/OutStream.h> +#include <rfb/Exception.h> #include <rfb/ServerParams.h> #include <rfb/PixelBuffer.h> #include <rfb/HextileDecoder.h> +#include <rfb/hextileConstants.h> using namespace rfb; -#define BPP 8 -#include <rfb/hextileDecode.h> -#undef BPP -#define BPP 16 -#include <rfb/hextileDecode.h> -#undef BPP -#define BPP 32 -#include <rfb/hextileDecode.h> -#undef BPP - HextileDecoder::HextileDecoder() : Decoder(DecoderPlain) { } @@ -127,8 +120,87 @@ void HextileDecoder::decodeRect(const Rect& r, const void* buffer, rdr::MemInStream is(buffer, buflen); const PixelFormat& pf = server.pf(); switch (pf.bpp) { - case 8: hextileDecode8 (r, &is, pf, pb); break; - case 16: hextileDecode16(r, &is, pf, pb); break; - case 32: hextileDecode32(r, &is, pf, pb); break; + case 8: hextileDecode<rdr::U8 >(r, &is, pf, pb); break; + case 16: hextileDecode<rdr::U16>(r, &is, pf, pb); break; + case 32: hextileDecode<rdr::U32>(r, &is, pf, pb); break; + } +} + +template<class T> +inline T HextileDecoder::readPixel(rdr::InStream* is) +{ + if (sizeof(T) == 1) + return is->readOpaque8(); + if (sizeof(T) == 2) + return is->readOpaque16(); + if (sizeof(T) == 4) + return is->readOpaque32(); +} + +template<class T> +void HextileDecoder::hextileDecode(const Rect& r, rdr::InStream* is, + const PixelFormat& pf, + ModifiablePixelBuffer* pb) +{ + Rect t; + T bg = 0; + T fg = 0; + T buf[16 * 16]; + + for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { + + t.br.y = __rfbmin(r.br.y, t.tl.y + 16); + + for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) { + + t.br.x = __rfbmin(r.br.x, t.tl.x + 16); + + int tileType = is->readU8(); + + if (tileType & hextileRaw) { + is->readBytes(buf, t.area() * sizeof(T)); + pb->imageRect(pf, t, buf); + continue; + } + + if (tileType & hextileBgSpecified) + bg = readPixel<T>(is); + + int len = t.area(); + T* ptr = buf; + while (len-- > 0) *ptr++ = bg; + + if (tileType & hextileFgSpecified) + fg = readPixel<T>(is); + + if (tileType & hextileAnySubrects) { + int nSubrects = is->readU8(); + + for (int i = 0; i < nSubrects; i++) { + + if (tileType & hextileSubrectsColoured) + fg = readPixel<T>(is); + + int xy = is->readU8(); + int wh = is->readU8(); + + int x = ((xy >> 4) & 15); + int y = (xy & 15); + int w = ((wh >> 4) & 15) + 1; + int h = (wh & 15) + 1; + if (x + w > 16 || y + h > 16) { + throw rfb::Exception("HEXTILE_DECODE: Hextile out of bounds"); + } + T* ptr = buf + y * t.width() + x; + int rowAdd = t.width() - w; + while (h-- > 0) { + int len = w; + while (len-- > 0) *ptr++ = fg; + ptr += rowAdd; + } + } + } + pb->imageRect(pf, t, buf); + } } } diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h index 2c42be54..e8961d73 100644 --- a/common/rfb/HextileDecoder.h +++ b/common/rfb/HextileDecoder.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,8 @@ namespace rfb { + class PixelFormat; + class HextileDecoder : public Decoder { public: HextileDecoder(); @@ -31,6 +34,13 @@ namespace rfb { virtual void decodeRect(const Rect& r, const void* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); + private: + template<class T> + inline T readPixel(rdr::InStream* is); + template<class T> + void hextileDecode(const Rect& r, rdr::InStream* is, + const PixelFormat& pf, + ModifiablePixelBuffer* pb); }; } #endif diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index f9db06b8..b2b0f3a4 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2005 Constantin Kaplinsky. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,8 +25,10 @@ #include <rfb/encodings.h> #include <rfb/SConnection.h> #include <rfb/HextileEncoder.h> +#include <rfb/Palette.h> #include <rfb/PixelBuffer.h> #include <rfb/Configuration.h> +#include <rfb/hextileConstants.h> using namespace rfb; @@ -36,19 +38,6 @@ BoolParameter improvedHextile("ImprovedHextile", "ratios by the cost of using more CPU time", true); -#define BPP 8 -#include <rfb/hextileEncode.h> -#include <rfb/hextileEncodeBetter.h> -#undef BPP -#define BPP 16 -#include <rfb/hextileEncode.h> -#include <rfb/hextileEncodeBetter.h> -#undef BPP -#define BPP 32 -#include <rfb/hextileEncode.h> -#include <rfb/hextileEncodeBetter.h> -#undef BPP - HextileEncoder::HextileEncoder(SConnection* conn) : Encoder(conn, encodingHextile, EncoderPlain) { @@ -70,23 +59,23 @@ void HextileEncoder::writeRect(const PixelBuffer* pb, switch (pb->getPF().bpp) { case 8: if (improvedHextile) { - hextileEncodeBetter8(os, pb); + hextileEncodeBetter<rdr::U8>(os, pb); } else { - hextileEncode8(os, pb); + hextileEncode<rdr::U8>(os, pb); } break; case 16: if (improvedHextile) { - hextileEncodeBetter16(os, pb); + hextileEncodeBetter<rdr::U16>(os, pb); } else { - hextileEncode16(os, pb); + hextileEncode<rdr::U16>(os, pb); } break; case 32: if (improvedHextile) { - hextileEncodeBetter32(os, pb); + hextileEncodeBetter<rdr::U32>(os, pb); } else { - hextileEncode32(os, pb); + hextileEncode<rdr::U32>(os, pb); } break; } @@ -110,3 +99,496 @@ void HextileEncoder::writeSolidRect(int width, int height, while (tiles--) os->writeU8(0); } + +template<class T> +inline void HextileEncoder::writePixel(rdr::OutStream* os, T pixel) +{ + if (sizeof(T) == 1) + os->writeOpaque8(pixel); + else if (sizeof(T) == 2) + os->writeOpaque16(pixel); + else if (sizeof(T) == 4) + os->writeOpaque32(pixel); +} + +template<class T> +void HextileEncoder::hextileEncode(rdr::OutStream* os, + const PixelBuffer* pb) +{ + Rect t; + T buf[256]; + T oldBg = 0, oldFg = 0; + bool oldBgValid = false; + bool oldFgValid = false; + rdr::U8 encoded[256*sizeof(T)]; + + for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) { + + t.br.y = __rfbmin(pb->height(), t.tl.y + 16); + + for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) { + + t.br.x = __rfbmin(pb->width(), t.tl.x + 16); + + pb->getImage(buf, t); + + T bg = 0, fg = 0; + int tileType = testTileType(buf, t.width(), t.height(), &bg, &fg); + + if (!oldBgValid || oldBg != bg) { + tileType |= hextileBgSpecified; + oldBg = bg; + oldBgValid = true; + } + + int encodedLen = 0; + + if (tileType & hextileAnySubrects) { + + if (tileType & hextileSubrectsColoured) { + oldFgValid = false; + } else { + if (!oldFgValid || oldFg != fg) { + tileType |= hextileFgSpecified; + oldFg = fg; + oldFgValid = true; + } + } + + encodedLen = hextileEncodeTile(buf, t.width(), t.height(), + tileType, encoded, bg); + + if (encodedLen < 0) { + pb->getImage(buf, t); + os->writeU8(hextileRaw); + os->writeBytes(buf, t.width() * t.height() * sizeof(T)); + oldBgValid = oldFgValid = false; + continue; + } + } + + os->writeU8(tileType); + if (tileType & hextileBgSpecified) writePixel(os, bg); + if (tileType & hextileFgSpecified) writePixel(os, fg); + if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen); + } + } +} + +template<class T> +int HextileEncoder::hextileEncodeTile(T* data, int w, int h, + int tileType, rdr::U8* encoded, + T bg) +{ + rdr::U8* nSubrectsPtr = encoded; + *nSubrectsPtr = 0; + encoded++; + + for (int y = 0; y < h; y++) + { + int x = 0; + while (x < w) { + if (*data == bg) { + x++; + data++; + continue; + } + + // Find horizontal subrect first + T* ptr = data+1; + T* eol = data+w-x; + while (ptr < eol && *ptr == *data) ptr++; + int sw = ptr - data; + + ptr = data + w; + int sh = 1; + while (sh < h-y) { + eol = ptr + sw; + while (ptr < eol) + if (*ptr++ != *data) goto endOfSubrect; + ptr += w - sw; + sh++; + } + endOfSubrect: + + (*nSubrectsPtr)++; + + if (tileType & hextileSubrectsColoured) { + if (encoded - nSubrectsPtr + sizeof(T) > w*h*sizeof(T)) + return -1; + + if (sizeof(T) == 1) { + *encoded++ = *data; + } else if (sizeof(T) == 2) { + *encoded++ = ((rdr::U8*)data)[0]; + *encoded++ = ((rdr::U8*)data)[1]; + } else if (sizeof(T) == 4) { + *encoded++ = ((rdr::U8*)data)[0]; + *encoded++ = ((rdr::U8*)data)[1]; + *encoded++ = ((rdr::U8*)data)[2]; + *encoded++ = ((rdr::U8*)data)[3]; + } + } + + if ((size_t)(encoded - nSubrectsPtr + 2) > w*h*sizeof(T)) + return -1; + *encoded++ = (x << 4) | y; + *encoded++ = ((sw-1) << 4) | (sh-1); + + ptr = data+w; + T* eor = data+w*sh; + while (ptr < eor) { + eol = ptr + sw; + while (ptr < eol) *ptr++ = bg; + ptr += w - sw; + } + x += sw; + data += sw; + } + } + return encoded - nSubrectsPtr; +} + +template<class T> +int HextileEncoder::testTileType(T* data, int w, int h, T* bg, T* fg) +{ + T pix1 = *data; + T* end = data + w * h; + + T* ptr = data + 1; + while (ptr < end && *ptr == pix1) + ptr++; + + if (ptr == end) { + *bg = pix1; + return 0; // solid-color tile + } + + int count1 = ptr - data; + int count2 = 1; + T pix2 = *ptr++; + int tileType = hextileAnySubrects; + + for (; ptr < end; ptr++) { + if (*ptr == pix1) { + count1++; + } else if (*ptr == pix2) { + count2++; + } else { + tileType |= hextileSubrectsColoured; + break; + } + } + + if (count1 >= count2) { + *bg = pix1; *fg = pix2; + } else { + *bg = pix2; *fg = pix1; + } + return tileType; +} + +// +// This class analyzes a separate tile and encodes its subrectangles. +// + +template<class T> +class HextileTile { + + public: + + HextileTile (); + + // + // Initialize existing object instance with new tile data. + // + void newTile(const T *src, int w, int h); + + // + // Flags can include: hextileRaw, hextileAnySubrects and + // hextileSubrectsColoured. Note that if hextileRaw is set, other + // flags make no sense. Also, hextileSubrectsColoured is meaningful + // only when hextileAnySubrects is set as well. + // + int getFlags() const { return m_flags; } + + // + // Returns the size of encoded subrects data, including subrect count. + // The size is zero if flags do not include hextileAnySubrects. + // + size_t getSize() const { return m_size; } + + // + // Return optimal background. + // + int getBackground() const { return m_background; } + + // + // Return foreground if flags include hextileSubrectsColoured. + // + int getForeground() const { return m_foreground; } + + // + // Encode subrects. This function may be called only if + // hextileAnySubrects bit is set in flags. The buffer size should be + // big enough to store at least the number of bytes returned by the + // getSize() method. + // + void encode(rdr::U8* dst) const; + + protected: + + // + // Analyze the tile pixels, fill in all the data fields. + // + void analyze(); + + const T *m_tile; + int m_width; + int m_height; + + size_t m_size; + int m_flags; + T m_background; + T m_foreground; + + int m_numSubrects; + rdr::U8 m_coords[256 * 2]; + T m_colors[256]; + + private: + + bool m_processed[16][16]; + Palette m_pal; +}; + +template<class T> +HextileTile<T>::HextileTile() + : m_tile(NULL), m_width(0), m_height(0), + m_size(0), m_flags(0), m_background(0), m_foreground(0), + m_numSubrects(0) +{ +} + +template<class T> +void HextileTile<T>::newTile(const T *src, int w, int h) +{ + m_tile = src; + m_width = w; + m_height = h; + + analyze(); +} + +template<class T> +void HextileTile<T>::analyze() +{ + assert(m_tile && m_width && m_height); + + const T *ptr = m_tile; + const T *end = &m_tile[m_width * m_height]; + T color = *ptr++; + while (ptr != end && *ptr == color) + ptr++; + + // Handle solid tile + if (ptr == end) { + m_background = m_tile[0]; + m_flags = 0; + m_size = 0; + return; + } + + // Compute number of complete rows of the same color, at the top + int y = (ptr - m_tile) / m_width; + + T *colorsPtr = m_colors; + rdr::U8 *coordsPtr = m_coords; + m_pal.clear(); + m_numSubrects = 0; + + // Have we found the first subrect already? + if (y > 0) { + *colorsPtr++ = color; + *coordsPtr++ = 0; + *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F)); + m_pal.insert(color, 1); + m_numSubrects++; + } + + memset(m_processed, 0, 16 * 16 * sizeof(bool)); + + int x, sx, sy, sw, sh, max_x; + + for (; y < m_height; y++) { + for (x = 0; x < m_width; x++) { + // Skip pixels that were processed earlier + if (m_processed[y][x]) { + continue; + } + // Determine dimensions of the horizontal subrect + color = m_tile[y * m_width + x]; + for (sx = x + 1; sx < m_width; sx++) { + if (m_tile[y * m_width + sx] != color) + break; + } + sw = sx - x; + max_x = sx; + for (sy = y + 1; sy < m_height; sy++) { + for (sx = x; sx < max_x; sx++) { + if (m_tile[sy * m_width + sx] != color) + goto done; + } + } + done: + sh = sy - y; + + // Save properties of this subrect + *colorsPtr++ = color; + *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F)); + *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F)); + + if (!m_pal.insert(color, 1) || + ((size_t)m_pal.size() > (48 + 2 * sizeof(T)*8))) { + // Handle palette overflow + m_flags = hextileRaw; + m_size = 0; + return; + } + + m_numSubrects++; + + // Mark pixels of this subrect as processed, below this row + for (sy = y + 1; sy < y + sh; sy++) { + for (sx = x; sx < x + sw; sx++) + m_processed[sy][sx] = true; + } + + // Skip processed pixels of this row + x += (sw - 1); + } + } + + // Save number of colors in this tile (should be no less than 2) + int numColors = m_pal.size(); + assert(numColors >= 2); + + m_background = (T)m_pal.getColour(0); + m_flags = hextileAnySubrects; + int numSubrects = m_numSubrects - m_pal.getCount(0); + + if (numColors == 2) { + // Monochrome tile + m_foreground = (T)m_pal.getColour(1); + m_size = 1 + 2 * numSubrects; + } else { + // Colored tile + m_flags |= hextileSubrectsColoured; + m_size = 1 + (2 + sizeof(T)) * numSubrects; + } +} + +template<class T> +void HextileTile<T>::encode(rdr::U8 *dst) const +{ + assert(m_numSubrects && (m_flags & hextileAnySubrects)); + + // Zero subrects counter + rdr::U8 *numSubrectsPtr = dst; + *dst++ = 0; + + for (int i = 0; i < m_numSubrects; i++) { + if (m_colors[i] == m_background) + continue; + + if (m_flags & hextileSubrectsColoured) { + if (sizeof(T) == 1) { + *dst++ = m_colors[i]; + } else if (sizeof(T) == 2) { + *dst++ = ((rdr::U8*)&m_colors[i])[0]; + *dst++ = ((rdr::U8*)&m_colors[i])[1]; + } else if (sizeof(T) == 4) { + *dst++ = ((rdr::U8*)&m_colors[i])[0]; + *dst++ = ((rdr::U8*)&m_colors[i])[1]; + *dst++ = ((rdr::U8*)&m_colors[i])[2]; + *dst++ = ((rdr::U8*)&m_colors[i])[3]; + } + } + *dst++ = m_coords[i * 2]; + *dst++ = m_coords[i * 2 + 1]; + + (*numSubrectsPtr)++; + } + + assert((size_t)(dst - numSubrectsPtr) == m_size); +} + +// +// Main encoding function. +// + +template<class T> +void HextileEncoder::hextileEncodeBetter(rdr::OutStream* os, + const PixelBuffer* pb) +{ + Rect t; + T buf[256]; + T oldBg = 0, oldFg = 0; + bool oldBgValid = false; + bool oldFgValid = false; + rdr::U8 encoded[256*sizeof(T)]; + + HextileTile<T> tile; + + for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) { + + t.br.y = __rfbmin(pb->height(), t.tl.y + 16); + + for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) { + + t.br.x = __rfbmin(pb->width(), t.tl.x + 16); + + pb->getImage(buf, t); + + tile.newTile(buf, t.width(), t.height()); + int tileType = tile.getFlags(); + size_t encodedLen = tile.getSize(); + + if ( (tileType & hextileRaw) != 0 || + encodedLen >= t.width() * t.height() * sizeof(T)) { + os->writeU8(hextileRaw); + os->writeBytes(buf, t.width() * t.height() * sizeof(T)); + oldBgValid = oldFgValid = false; + continue; + } + + T bg = tile.getBackground(); + T fg = 0; + + if (!oldBgValid || oldBg != bg) { + tileType |= hextileBgSpecified; + oldBg = bg; + oldBgValid = true; + } + + if (tileType & hextileAnySubrects) { + if (tileType & hextileSubrectsColoured) { + oldFgValid = false; + } else { + fg = tile.getForeground(); + if (!oldFgValid || oldFg != fg) { + tileType |= hextileFgSpecified; + oldFg = fg; + oldFgValid = true; + } + } + tile.encode(encoded); + } + + os->writeU8(tileType); + if (tileType & hextileBgSpecified) writePixel(os, bg); + if (tileType & hextileFgSpecified) writePixel(os, fg); + if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen); + } + } +} diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h index 393ab23b..64cc0de3 100644 --- a/common/rfb/HextileEncoder.h +++ b/common/rfb/HextileEncoder.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,20 @@ namespace rfb { virtual void writeSolidRect(int width, int height, const PixelFormat& pf, const rdr::U8* colour); + private: + template<class T> + inline void writePixel(rdr::OutStream* os, T pixel); + + template<class T> + void hextileEncode(rdr::OutStream* os, const PixelBuffer* pb); + template<class T> + int hextileEncodeTile(T* data, int w, int h, int tileType, + rdr::U8* encoded, T bg); + template<class T> + int testTileType(T* data, int w, int h, T* bg, T* fg); + + template<class T> + void hextileEncodeBetter(rdr::OutStream* os, const PixelBuffer* pb); }; } #endif diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index 0abf53b6..5a3f0147 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2009-2014 Pierre Ossman for Cendio AB + * Copyright 2009-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -710,41 +710,133 @@ bool PixelFormat::isSane(void) return true; } -// Preprocessor generated, optimised methods - -#define INBPP 8 -#define OUTBPP 8 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#define OUTBPP 16 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#define OUTBPP 32 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#undef INBPP - -#define INBPP 16 -#define OUTBPP 8 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#define OUTBPP 16 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#define OUTBPP 32 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#undef INBPP - -#define INBPP 32 -#define OUTBPP 8 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#define OUTBPP 16 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#define OUTBPP 32 -#include "PixelFormatBPP.cxx" -#undef OUTBPP -#undef INBPP +static inline uint8_t swap(uint8_t n) +{ + return n; +} + +static inline uint16_t swap(uint16_t n) +{ + return (((n) & 0xff) << 8) | (((n) >> 8) & 0xff); +} + +static inline uint32_t swap(uint32_t n) +{ + return ((n) >> 24) | (((n) & 0x00ff0000) >> 8) | + (((n) & 0x0000ff00) << 8) | ((n) << 24); +} + +template<class T> +void PixelFormat::directBufferFromBufferFrom888(T* dst, + const PixelFormat &srcPF, + const uint8_t* src, + int w, int h, + int dstStride, + int srcStride) const +{ + const uint8_t *r, *g, *b; + int dstPad, srcPad; + + const uint8_t *redDownTable, *greenDownTable, *blueDownTable; + + redDownTable = &downconvTable[(redBits-1)*256]; + greenDownTable = &downconvTable[(greenBits-1)*256]; + blueDownTable = &downconvTable[(blueBits-1)*256]; + + if (srcPF.bigEndian) { + r = src + (24 - srcPF.redShift)/8; + g = src + (24 - srcPF.greenShift)/8; + b = src + (24 - srcPF.blueShift)/8; + } else { + r = src + srcPF.redShift/8; + g = src + srcPF.greenShift/8; + b = src + srcPF.blueShift/8; + } + + dstPad = (dstStride - w); + srcPad = (srcStride - w) * 4; + while (h--) { + int w_ = w; + while (w_--) { + T d; + + d = redDownTable[*r] << redShift; + d |= greenDownTable[*g] << greenShift; + d |= blueDownTable[*b] << blueShift; + + if (endianMismatch) + d = swap(d); + + *dst = d; + dst++; + r += 4; + g += 4; + b += 4; + } + dst += dstPad; + r += srcPad; + g += srcPad; + b += srcPad; + } +} + +template<class T> +void PixelFormat::directBufferFromBufferTo888(uint8_t* dst, + const PixelFormat &srcPF, + const T* src, + int w, int h, + int dstStride, + int srcStride) const +{ + uint8_t *r, *g, *b, *x; + int dstPad, srcPad; + + const uint8_t *redUpTable, *greenUpTable, *blueUpTable; + + redUpTable = &upconvTable[(srcPF.redBits-1)*256]; + greenUpTable = &upconvTable[(srcPF.greenBits-1)*256]; + blueUpTable = &upconvTable[(srcPF.blueBits-1)*256]; + + if (bigEndian) { + r = dst + (24 - redShift)/8; + g = dst + (24 - greenShift)/8; + b = dst + (24 - blueShift)/8; + x = dst + (24 - (48 - redShift - greenShift - blueShift))/8; + } else { + r = dst + redShift/8; + g = dst + greenShift/8; + b = dst + blueShift/8; + x = dst + (48 - redShift - greenShift - blueShift)/8; + } + + dstPad = (dstStride - w) * 4; + srcPad = (srcStride - w); + while (h--) { + int w_ = w; + while (w_--) { + T s; + + s = *src; + + if (srcPF.endianMismatch) + s = swap(s); + + *r = redUpTable[(s >> srcPF.redShift) & 0xff]; + *g = greenUpTable[(s >> srcPF.greenShift) & 0xff]; + *b = blueUpTable[(s >> srcPF.blueShift) & 0xff]; + *x = 0; + + r += 4; + g += 4; + b += 4; + x += 4; + src++; + } + r += dstPad; + g += dstPad; + b += dstPad; + x += dstPad; + src += srcPad; + } +} diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h index 5b4b6332..ceb6c010 100644 --- a/common/rfb/PixelFormat.h +++ b/common/rfb/PixelFormat.h @@ -1,6 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2009-2014 Pierre Ossman for Cendio AB + * Copyright 2009-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -91,26 +91,14 @@ namespace rfb { bool isSane(void); private: - // Preprocessor generated, optimised methods - - void directBufferFromBufferFrom888(rdr::U8* dst, const PixelFormat &srcPF, - const rdr::U8* src, int w, int h, - int dstStride, int srcStride) const; - void directBufferFromBufferFrom888(rdr::U16* dst, const PixelFormat &srcPF, - const rdr::U8* src, int w, int h, - int dstStride, int srcStride) const; - void directBufferFromBufferFrom888(rdr::U32* dst, const PixelFormat &srcPF, + // Templated, optimised methods + template<class T> + void directBufferFromBufferFrom888(T* dst, const PixelFormat &srcPF, const rdr::U8* src, int w, int h, int dstStride, int srcStride) const; - - void directBufferFromBufferTo888(rdr::U8* dst, const PixelFormat &srcPF, - const rdr::U8* src, int w, int h, - int dstStride, int srcStride) const; - void directBufferFromBufferTo888(rdr::U8* dst, const PixelFormat &srcPF, - const rdr::U16* src, int w, int h, - int dstStride, int srcStride) const; + template<class T> void directBufferFromBufferTo888(rdr::U8* dst, const PixelFormat &srcPF, - const rdr::U32* src, int w, int h, + const T* src, int w, int h, int dstStride, int srcStride) const; public: diff --git a/common/rfb/PixelFormatBPP.cxx b/common/rfb/PixelFormatBPP.cxx deleted file mode 100644 index c8e432df..00000000 --- a/common/rfb/PixelFormatBPP.cxx +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright 2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) - -#define UIN CONCAT2E(U,INBPP) -#define UOUT CONCAT2E(U,OUTBPP) - -#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff)) -#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \ - (((n) & 0x0000ff00) << 8) | ((n) << 24)) - -#define SWAPIN CONCAT2E(SWAP,INBPP) -#define SWAPOUT CONCAT2E(SWAP,OUTBPP) - -#if INBPP == 32 - -void PixelFormat::directBufferFromBufferFrom888(rdr::UOUT* dst, - const PixelFormat &srcPF, - const rdr::U8* src, - int w, int h, - int dstStride, - int srcStride) const -{ - const rdr::U8 *r, *g, *b; - int dstPad, srcPad; - - const rdr::U8 *redDownTable, *greenDownTable, *blueDownTable; - - redDownTable = &downconvTable[(redBits-1)*256]; - greenDownTable = &downconvTable[(greenBits-1)*256]; - blueDownTable = &downconvTable[(blueBits-1)*256]; - - if (srcPF.bigEndian) { - r = src + (24 - srcPF.redShift)/8; - g = src + (24 - srcPF.greenShift)/8; - b = src + (24 - srcPF.blueShift)/8; - } else { - r = src + srcPF.redShift/8; - g = src + srcPF.greenShift/8; - b = src + srcPF.blueShift/8; - } - - dstPad = (dstStride - w); - srcPad = (srcStride - w) * 4; - while (h--) { - int w_ = w; - while (w_--) { - rdr::UOUT d; - - d = redDownTable[*r] << redShift; - d |= greenDownTable[*g] << greenShift; - d |= blueDownTable[*b] << blueShift; - -#if OUTBPP != 8 - if (endianMismatch) - d = SWAPOUT(d); -#endif - - *dst = d; - - dst++; - r += 4; - g += 4; - b += 4; - } - dst += dstPad; - r += srcPad; - g += srcPad; - b += srcPad; - } -} - -#endif /* INBPP == 32 */ - -#if OUTBPP == 32 - -void PixelFormat::directBufferFromBufferTo888(rdr::U8* dst, - const PixelFormat &srcPF, - const rdr::UIN* src, - int w, int h, - int dstStride, - int srcStride) const -{ - rdr::U8 *r, *g, *b, *x; - int dstPad, srcPad; - - const rdr::U8 *redUpTable, *greenUpTable, *blueUpTable; - - redUpTable = &upconvTable[(srcPF.redBits-1)*256]; - greenUpTable = &upconvTable[(srcPF.greenBits-1)*256]; - blueUpTable = &upconvTable[(srcPF.blueBits-1)*256]; - - if (bigEndian) { - r = dst + (24 - redShift)/8; - g = dst + (24 - greenShift)/8; - b = dst + (24 - blueShift)/8; - x = dst + (24 - (48 - redShift - greenShift - blueShift))/8; - } else { - r = dst + redShift/8; - g = dst + greenShift/8; - b = dst + blueShift/8; - x = dst + (48 - redShift - greenShift - blueShift)/8; - } - - dstPad = (dstStride - w) * 4; - srcPad = (srcStride - w); - while (h--) { - int w_ = w; - while (w_--) { - rdr::UIN s; - - s = *src; - -#if INBPP != 8 - if (srcPF.endianMismatch) - s = SWAPIN(s); -#endif - - *r = redUpTable[(s >> srcPF.redShift) & 0xff]; - *g = greenUpTable[(s >> srcPF.greenShift) & 0xff]; - *b = blueUpTable[(s >> srcPF.blueShift) & 0xff]; - *x = 0; - - r += 4; - g += 4; - b += 4; - x += 4; - src++; - } - r += dstPad; - g += dstPad; - b += dstPad; - x += dstPad; - src += srcPad; - } -} - -#endif /* OUTBPP == 32 */ diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx index a01cbe74..1384a2be 100644 --- a/common/rfb/RREDecoder.cxx +++ b/common/rfb/RREDecoder.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,22 +25,13 @@ #include <rdr/MemInStream.h> #include <rdr/OutStream.h> +#include <rfb/Exception.h> #include <rfb/ServerParams.h> #include <rfb/PixelBuffer.h> #include <rfb/RREDecoder.h> using namespace rfb; -#define BPP 8 -#include <rfb/rreDecode.h> -#undef BPP -#define BPP 16 -#include <rfb/rreDecode.h> -#undef BPP -#define BPP 32 -#include <rfb/rreDecode.h> -#undef BPP - RREDecoder::RREDecoder() : Decoder(DecoderPlain) { } @@ -81,8 +73,42 @@ void RREDecoder::decodeRect(const Rect& r, const void* buffer, rdr::MemInStream is(buffer, buflen); const PixelFormat& pf = server.pf(); switch (pf.bpp) { - case 8: rreDecode8 (r, &is, pf, pb); break; - case 16: rreDecode16(r, &is, pf, pb); break; - case 32: rreDecode32(r, &is, pf, pb); break; + case 8: rreDecode<rdr::U8 >(r, &is, pf, pb); break; + case 16: rreDecode<rdr::U16>(r, &is, pf, pb); break; + case 32: rreDecode<rdr::U32>(r, &is, pf, pb); break; + } +} + +template<class T> +inline T RREDecoder::readPixel(rdr::InStream* is) +{ + if (sizeof(T) == 1) + return is->readOpaque8(); + if (sizeof(T) == 2) + return is->readOpaque16(); + if (sizeof(T) == 4) + return is->readOpaque32(); +} + +template<class T> +void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is, + const PixelFormat& pf, + ModifiablePixelBuffer* pb) +{ + int nSubrects = is->readU32(); + T bg = readPixel<T>(is); + pb->fillRect(pf, r, &bg); + + for (int i = 0; i < nSubrects; i++) { + T pix = readPixel<T>(is); + int x = is->readU16(); + int y = is->readU16(); + int w = is->readU16(); + int h = is->readU16(); + + if (((x+w) > r.width()) || ((y+h) > r.height())) + throw Exception ("RRE decode error"); + + pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), &pix); } } diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h index b8ec18f6..05acbc24 100644 --- a/common/rfb/RREDecoder.h +++ b/common/rfb/RREDecoder.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,8 @@ namespace rfb { + class PixelFormat; + class RREDecoder : public Decoder { public: RREDecoder(); @@ -31,6 +34,12 @@ namespace rfb { virtual void decodeRect(const Rect& r, const void* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); + private: + template<class T> + inline T readPixel(rdr::InStream* is); + template<class T> + void rreDecode(const Rect& r, rdr::InStream* is, + const PixelFormat& pf, ModifiablePixelBuffer* pb); }; } #endif diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx index 31f94e7c..bbad7c7e 100644 --- a/common/rfb/RREEncoder.cxx +++ b/common/rfb/RREEncoder.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,16 +31,6 @@ using namespace rfb; -#define BPP 8 -#include <rfb/rreEncode.h> -#undef BPP -#define BPP 16 -#include <rfb/rreEncode.h> -#undef BPP -#define BPP 32 -#include <rfb/rreEncode.h> -#undef BPP - RREEncoder::RREEncoder(SConnection* conn) : Encoder(conn, encodingRRE, EncoderPlain) { @@ -89,13 +79,13 @@ void RREEncoder::writeRect(const PixelBuffer* pb, const Palette& palette) int nSubrects = -1; switch (pb->getPF().bpp) { case 8: - nSubrects = rreEncode8((rdr::U8*)imageBuf, w, h, &mos, bg); + nSubrects = rreEncode<rdr::U8>((rdr::U8*)imageBuf, w, h, &mos, bg); break; case 16: - nSubrects = rreEncode16((rdr::U16*)imageBuf, w, h, &mos, bg); + nSubrects = rreEncode<rdr::U16>((rdr::U16*)imageBuf, w, h, &mos, bg); break; case 32: - nSubrects = rreEncode32((rdr::U32*)imageBuf, w, h, &mos, bg); + nSubrects = rreEncode<rdr::U32>((rdr::U32*)imageBuf, w, h, &mos, bg); break; } @@ -118,3 +108,93 @@ void RREEncoder::writeSolidRect(int /*width*/, int /*height*/, os->writeU32(0); os->writeBytes(colour, pf.bpp/8); } + +template<class T> +inline void RREEncoder::writePixel(rdr::OutStream* os, T pixel) +{ + if (sizeof(T) == 1) + os->writeOpaque8(pixel); + else if (sizeof(T) == 2) + os->writeOpaque16(pixel); + else if (sizeof(T) == 4) + os->writeOpaque32(pixel); +} + +template<class T> +int RREEncoder::rreEncode(T* data, int w, int h, + rdr::OutStream* os, T bg) +{ + writePixel(os, bg); + + int nSubrects = 0; + + for (int y = 0; y < h; y++) + { + int x = 0; + while (x < w) { + if (*data == bg) { + x++; + data++; + continue; + } + + // Find horizontal subrect first + T* ptr = data+1; + T* eol = data+w-x; + while (ptr < eol && *ptr == *data) ptr++; + int sw = ptr - data; + + ptr = data + w; + int sh = 1; + while (sh < h-y) { + eol = ptr + sw; + while (ptr < eol) + if (*ptr++ != *data) goto endOfHorizSubrect; + ptr += w - sw; + sh++; + } + endOfHorizSubrect: + + // Find vertical subrect + int vh; + for (vh = sh; vh < h-y; vh++) + if (data[vh*w] != *data) break; + + if (vh != sh) { + ptr = data+1; + int vw; + for (vw = 1; vw < sw; vw++) { + for (int i = 0; i < vh; i++) + if (ptr[i*w] != *data) goto endOfVertSubrect; + ptr++; + } + endOfVertSubrect: + + // If vertical subrect bigger than horizontal then use that. + if (sw*sh < vw*vh) { + sw = vw; + sh = vh; + } + } + + nSubrects++; + writePixel(os, *data); + os->writeU16(x); + os->writeU16(y); + os->writeU16(sw); + os->writeU16(sh); + + ptr = data+w; + T* eor = data+w*sh; + while (ptr < eor) { + eol = ptr + sw; + while (ptr < eol) *ptr++ = bg; + ptr += w - sw; + } + x += sw; + data += sw; + } + } + + return nSubrects; +} diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h index c0de9995..767e7348 100644 --- a/common/rfb/RREEncoder.h +++ b/common/rfb/RREEncoder.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +35,11 @@ namespace rfb { const PixelFormat& pf, const rdr::U8* colour); private: + template<class T> + inline void writePixel(rdr::OutStream* os, T pixel); + template<class T> + int rreEncode(T* data, int w, int h, rdr::OutStream* os, T bg); + private: rdr::MemOutStream mos; ManagedPixelBuffer bufferCopy; }; diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index 69971dbc..f56a4284 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright 2004-2005 Cendio AB. - * Copyright 2009-2015 Pierre Ossman for Cendio AB + * Copyright 2009-2022 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 @@ -40,16 +40,6 @@ using namespace rfb; static const int TIGHT_MAX_WIDTH = 2048; static const int TIGHT_MIN_TO_COMPRESS = 12; -#define BPP 8 -#include <rfb/tightDecode.h> -#undef BPP -#define BPP 16 -#include <rfb/tightDecode.h> -#undef BPP -#define BPP 32 -#include <rfb/tightDecode.h> -#undef BPP - TightDecoder::TightDecoder() : Decoder(DecoderPartiallyOrdered) { } @@ -509,3 +499,144 @@ rdr::U32 TightDecoder::readCompact(rdr::InStream* is) return result; } + +void +TightDecoder::FilterGradient24(const rdr::U8 *inbuf, + const PixelFormat& pf, rdr::U32* outbuf, + int stride, const Rect& r) +{ + int x, y, c; + rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; + rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; + rdr::U8 pix[3]; + int est[3]; + + memset(prevRow, 0, sizeof(prevRow)); + + // Set up shortcut variables + int rectHeight = r.height(); + int rectWidth = r.width(); + + for (y = 0; y < rectHeight; y++) { + for (x = 0; x < rectWidth; x++) { + /* First pixel in a row */ + if (x == 0) { + for (c = 0; c < 3; c++) { + pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c]; + thisRow[c] = pix[c]; + } + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); + continue; + } + + for (c = 0; c < 3; c++) { + est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c]; + if (est[c] > 0xff) { + est[c] = 0xff; + } else if (est[c] < 0) { + est[c] = 0; + } + pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c]; + thisRow[x*3+c] = pix[c]; + } + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); + } + + memcpy(prevRow, thisRow, sizeof(prevRow)); + } +} + +template<class T> +void TightDecoder::FilterGradient(const rdr::U8* inbuf, + const PixelFormat& pf, T* outbuf, + int stride, const Rect& r) +{ + int x, y, c; + static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; + static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; + rdr::U8 pix[3]; + int est[3]; + + memset(prevRow, 0, sizeof(prevRow)); + + // Set up shortcut variables + int rectHeight = r.height(); + int rectWidth = r.width(); + + for (y = 0; y < rectHeight; y++) { + for (x = 0; x < rectWidth; x++) { + /* First pixel in a row */ + if (x == 0) { + pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1); + for (c = 0; c < 3; c++) + pix[c] += prevRow[c]; + + memcpy(thisRow, pix, sizeof(pix)); + + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); + + continue; + } + + for (c = 0; c < 3; c++) { + est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c]; + if (est[c] > 255) { + est[c] = 255; + } else if (est[c] < 0) { + est[c] = 0; + } + } + + pf.rgbFromBuffer(pix, &inbuf[y*rectWidth+x], 1); + for (c = 0; c < 3; c++) + pix[c] += est[c]; + + memcpy(&thisRow[x*3], pix, sizeof(pix)); + + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); + } + + memcpy(prevRow, thisRow, sizeof(prevRow)); + } +} + +template<class T> +void TightDecoder::FilterPalette(const T* palette, int palSize, + const rdr::U8* inbuf, T* outbuf, + int stride, const Rect& r) +{ + // Indexed color + int x, h = r.height(), w = r.width(), b, pad = stride - w; + T* ptr = outbuf; + rdr::U8 bits; + const rdr::U8* srcPtr = inbuf; + if (palSize <= 2) { + // 2-color palette + while (h > 0) { + for (x = 0; x < w / 8; x++) { + bits = *srcPtr++; + for (b = 7; b >= 0; b--) { + *ptr++ = palette[bits >> b & 1]; + } + } + if (w % 8 != 0) { + bits = *srcPtr++; + for (b = 7; b >= 8 - w % 8; b--) { + *ptr++ = palette[bits >> b & 1]; + } + } + ptr += pad; + h--; + } + } else { + // 256-color palette + while (h > 0) { + T *endOfRow = ptr + w; + while (ptr < endOfRow) { + *ptr++ = palette[*srcPtr++]; + } + ptr += pad; + h--; + } + } +} diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h index 763c82d6..47d65d6f 100644 --- a/common/rfb/TightDecoder.h +++ b/common/rfb/TightDecoder.h @@ -1,6 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2009-2015 Pierre Ossman for Cendio AB + * Copyright 2009-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,19 +50,13 @@ namespace rfb { void FilterGradient24(const rdr::U8* inbuf, const PixelFormat& pf, rdr::U32* outbuf, int stride, const Rect& r); + template<class T> void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf, - rdr::U16* outbuf, int stride, const Rect& r); - void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf, - rdr::U32* outbuf, int stride, const Rect& r); + T* outbuf, int stride, const Rect& r); - void FilterPalette(const rdr::U8* palette, int palSize, - const rdr::U8* inbuf, rdr::U8* outbuf, - int stride, const Rect& r); - void FilterPalette(const rdr::U16* palette, int palSize, - const rdr::U8* inbuf, rdr::U16* outbuf, - int stride, const Rect& r); - void FilterPalette(const rdr::U32* palette, int palSize, - const rdr::U8* inbuf, rdr::U32* outbuf, + template<class T> + void FilterPalette(const T* palette, int palSize, + const rdr::U8* inbuf, T* outbuf, int stride, const Rect& r); private: diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx index 94acd3d1..fe987e15 100644 --- a/common/rfb/TightEncoder.cxx +++ b/common/rfb/TightEncoder.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -274,16 +274,143 @@ void TightEncoder::flushZlibOutStream(rdr::OutStream* os_) memStream.clear(); } -// -// Including BPP-dependent implementation of the encoder. -// +template<class T> +void TightEncoder::writeMonoRect(int width, int height, + const T* buffer, int stride, + const PixelFormat& pf, + const Palette& palette) +{ + rdr::OutStream* os; + + const int streamId = 1; + T pal[2]; + + int length; + rdr::OutStream* zos; + + assert(palette.size() == 2); + + os = conn->getOutStream(); + + os->writeU8((streamId | tightExplicitFilter) << 4); + os->writeU8(tightFilterPalette); -#define BPP 8 -#include <rfb/TightEncoderBPP.cxx> -#undef BPP -#define BPP 16 -#include <rfb/TightEncoderBPP.cxx> -#undef BPP -#define BPP 32 -#include <rfb/TightEncoderBPP.cxx> -#undef BPP + // Write the palette + pal[0] = (T)palette.getColour(0); + pal[1] = (T)palette.getColour(1); + + os->writeU8(1); + writePixels((rdr::U8*)pal, pf, 2, os); + + // Set up compression + length = (width + 7)/8 * height; + zos = getZlibOutStream(streamId, monoZlibLevel, length); + + // Encode the data + T bg; + unsigned int value, mask; + int pad, aligned_width; + int x, y, bg_bits; + + bg = pal[0]; + aligned_width = width - width % 8; + pad = stride - width; + + for (y = 0; y < height; y++) { + for (x = 0; x < aligned_width; x += 8) { + for (bg_bits = 0; bg_bits < 8; bg_bits++) { + if (*buffer++ != bg) + break; + } + if (bg_bits == 8) { + zos->writeU8(0); + continue; + } + mask = 0x80 >> bg_bits; + value = mask; + for (bg_bits++; bg_bits < 8; bg_bits++) { + mask >>= 1; + if (*buffer++ != bg) { + value |= mask; + } + } + zos->writeU8(value); + } + + if (x < width) { + mask = 0x80; + value = 0; + + for (; x < width; x++) { + if (*buffer++ != bg) { + value |= mask; + } + mask >>= 1; + } + zos->writeU8(value); + } + + buffer += pad; + } + + // Finish the zlib stream + flushZlibOutStream(zos); +} + +template<class T> +void TightEncoder::writeIndexedRect(int width, int height, + const T* buffer, int stride, + const PixelFormat& pf, + const Palette& palette) +{ + rdr::OutStream* os; + + const int streamId = 2; + T pal[256]; + + rdr::OutStream* zos; + + int pad; + T prevColour; + unsigned char idx; + + assert(palette.size() > 0); + assert(palette.size() <= 256); + + os = conn->getOutStream(); + + os->writeU8((streamId | tightExplicitFilter) << 4); + os->writeU8(tightFilterPalette); + + // Write the palette + for (int i = 0; i < palette.size(); i++) + pal[i] = (T)palette.getColour(i); + + os->writeU8(palette.size() - 1); + writePixels((rdr::U8*)pal, pf, palette.size(), os); + + // Set up compression + zos = getZlibOutStream(streamId, idxZlibLevel, width * height); + + // Encode the data + pad = stride - width; + + prevColour = *buffer; + idx = palette.lookup(*buffer); + + while (height--) { + int w = width; + while (w--) { + if (*buffer != prevColour) { + prevColour = *buffer; + idx = palette.lookup(*buffer); + } + zos->writeU8(idx); + buffer++; + } + buffer += pad; + } + + // Finish the zlib stream + flushZlibOutStream(zos); +} diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h index b96bc4c6..2be2f6d4 100644 --- a/common/rfb/TightEncoder.h +++ b/common/rfb/TightEncoder.h @@ -1,6 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,22 +54,14 @@ namespace rfb { void flushZlibOutStream(rdr::OutStream* os); protected: - // Preprocessor generated, optimised methods + // Templated, optimised methods + template<class T> void writeMonoRect(int width, int height, - const rdr::U8* buffer, int stride, + const T* buffer, int stride, const PixelFormat& pf, const Palette& palette); - void writeMonoRect(int width, int height, - const rdr::U16* buffer, int stride, - const PixelFormat& pf, const Palette& palette); - void writeMonoRect(int width, int height, - const rdr::U32* buffer, int stride, - const PixelFormat& pf, const Palette& palette); - - void writeIndexedRect(int width, int height, - const rdr::U16* buffer, int stride, - const PixelFormat& pf, const Palette& palette); + template<class T> void writeIndexedRect(int width, int height, - const rdr::U32* buffer, int stride, + const T* buffer, int stride, const PixelFormat& pf, const Palette& palette); rdr::ZlibOutStream zlibStreams[4]; diff --git a/common/rfb/TightEncoderBPP.cxx b/common/rfb/TightEncoderBPP.cxx deleted file mode 100644 index 8874662c..00000000 --- a/common/rfb/TightEncoderBPP.cxx +++ /dev/null @@ -1,165 +0,0 @@ -/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. - * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) - -#define UBPP CONCAT2E(U,BPP) - -void TightEncoder::writeMonoRect(int width, int height, - const rdr::UBPP* buffer, int stride, - const PixelFormat& pf, - const Palette& palette) -{ - rdr::OutStream* os; - - const int streamId = 1; - rdr::UBPP pal[2]; - - int length; - rdr::OutStream* zos; - - assert(palette.size() == 2); - - os = conn->getOutStream(); - - os->writeU8((streamId | tightExplicitFilter) << 4); - os->writeU8(tightFilterPalette); - - // Write the palette - pal[0] = (rdr::UBPP)palette.getColour(0); - pal[1] = (rdr::UBPP)palette.getColour(1); - - os->writeU8(1); - writePixels((rdr::U8*)pal, pf, 2, os); - - // Set up compression - length = (width + 7)/8 * height; - zos = getZlibOutStream(streamId, monoZlibLevel, length); - - // Encode the data - rdr::UBPP bg; - unsigned int value, mask; - int pad, aligned_width; - int x, y, bg_bits; - - bg = pal[0]; - aligned_width = width - width % 8; - pad = stride - width; - - for (y = 0; y < height; y++) { - for (x = 0; x < aligned_width; x += 8) { - for (bg_bits = 0; bg_bits < 8; bg_bits++) { - if (*buffer++ != bg) - break; - } - if (bg_bits == 8) { - zos->writeU8(0); - continue; - } - mask = 0x80 >> bg_bits; - value = mask; - for (bg_bits++; bg_bits < 8; bg_bits++) { - mask >>= 1; - if (*buffer++ != bg) { - value |= mask; - } - } - zos->writeU8(value); - } - - if (x < width) { - mask = 0x80; - value = 0; - - for (; x < width; x++) { - if (*buffer++ != bg) { - value |= mask; - } - mask >>= 1; - } - zos->writeU8(value); - } - - buffer += pad; - } - - // Finish the zlib stream - flushZlibOutStream(zos); -} - -#if (BPP != 8) -void TightEncoder::writeIndexedRect(int width, int height, - const rdr::UBPP* buffer, int stride, - const PixelFormat& pf, - const Palette& palette) -{ - rdr::OutStream* os; - - const int streamId = 2; - rdr::UBPP pal[256]; - - rdr::OutStream* zos; - - int pad; - rdr::UBPP prevColour; - unsigned char idx; - - assert(palette.size() > 0); - assert(palette.size() <= 256); - - os = conn->getOutStream(); - - os->writeU8((streamId | tightExplicitFilter) << 4); - os->writeU8(tightFilterPalette); - - // Write the palette - for (int i = 0; i < palette.size(); i++) - pal[i] = (rdr::UBPP)palette.getColour(i); - - os->writeU8(palette.size() - 1); - writePixels((rdr::U8*)pal, pf, palette.size(), os); - - // Set up compression - zos = getZlibOutStream(streamId, idxZlibLevel, width * height); - - // Encode the data - pad = stride - width; - - prevColour = *buffer; - idx = palette.lookup(*buffer); - - while (height--) { - int w = width; - while (w--) { - if (*buffer != prevColour) { - prevColour = *buffer; - idx = palette.lookup(*buffer); - } - zos->writeU8(idx); - buffer++; - } - buffer += pad; - } - - // Finish the zlib stream - flushZlibOutStream(zos); -} -#endif // #if (BPP != 8) diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx index f5120e9c..c61b66bf 100644 --- a/common/rfb/ZRLEDecoder.cxx +++ b/common/rfb/ZRLEDecoder.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2017 Pierre Ossman for Cendio AB + * Copyright 2009-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,28 +50,23 @@ static inline rdr::U32 readOpaque24B(rdr::InStream* is) return r; } +template<class T> +static inline T readPixel(rdr::ZlibInStream* zis) +{ + if (sizeof(T) == 1) + return zis->readOpaque8(); + if (sizeof(T) == 2) + return zis->readOpaque16(); + if (sizeof(T) == 4) + return zis->readOpaque32(); +} + static inline void zlibHasData(rdr::ZlibInStream* zis, size_t length) { if (!zis->hasData(length)) throw Exception("ZRLE decode error"); } -#define BPP 8 -#include <rfb/zrleDecode.h> -#undef BPP -#define BPP 16 -#include <rfb/zrleDecode.h> -#undef BPP -#define BPP 32 -#include <rfb/zrleDecode.h> -#define CPIXEL 24A -#include <rfb/zrleDecode.h> -#undef CPIXEL -#define CPIXEL 24B -#include <rfb/zrleDecode.h> -#undef CPIXEL -#undef BPP - ZRLEDecoder::ZRLEDecoder() : Decoder(DecoderOrdered) { } @@ -111,32 +106,185 @@ void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer, rdr::MemInStream is(buffer, buflen); const rfb::PixelFormat& pf = server.pf(); switch (pf.bpp) { - case 8: zrleDecode8 (r, &is, &zis, pf, pb); break; - case 16: zrleDecode16(r, &is, &zis, pf, pb); break; - case 32: - { - if (pf.depth <= 24) { - Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); - bool fitsInLS3Bytes = maxPixel < (1<<24); - bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; - - if ((fitsInLS3Bytes && pf.isLittleEndian()) || - (fitsInMS3Bytes && pf.isBigEndian())) - { - zrleDecode24A(r, &is, &zis, pf, pb); - break; + case 8: zrleDecode<rdr::U8>(r, &is, &zis, pf, pb); break; + case 16: zrleDecode<rdr::U16>(r, &is, &zis, pf, pb); break; + case 32: zrleDecode<rdr::U32>(r, &is, &zis, pf, pb); break; + } +} + +template<class T> +void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is, + rdr::ZlibInStream* zis, + const PixelFormat& pf, + ModifiablePixelBuffer* pb) +{ + int length = is->readU32(); + zis->setUnderlying(is, length); + Rect t; + T buf[64 * 64]; + + Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); + bool fitsInLS3Bytes = maxPixel < (1<<24); + bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; + bool isLowCPixel = (sizeof(T) == 4) && + ((fitsInLS3Bytes && pf.isLittleEndian()) || + (fitsInMS3Bytes && pf.isBigEndian())); + bool isHighCPixel = (sizeof(T) == 4) && + ((fitsInLS3Bytes && pf.isBigEndian()) || + (fitsInMS3Bytes && pf.isLittleEndian())); + + for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) { + + t.br.y = __rfbmin(r.br.y, t.tl.y + 64); + + for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) { + + t.br.x = __rfbmin(r.br.x, t.tl.x + 64); + + zlibHasData(zis, 1); + int mode = zis->readU8(); + bool rle = mode & 128; + int palSize = mode & 127; + T palette[128]; + + if (isLowCPixel || isHighCPixel) + zlibHasData(zis, 3 * palSize); + else + zlibHasData(zis, sizeof(T) * palSize); + + for (int i = 0; i < palSize; i++) { + if (isLowCPixel) + palette[i] = readOpaque24A(zis); + else if (isHighCPixel) + palette[i] = readOpaque24B(zis); + else + palette[i] = readPixel<T>(zis); + } + + if (palSize == 1) { + T pix = palette[0]; + pb->fillRect(pf, t, &pix); + continue; + } + + if (!rle) { + if (palSize == 0) { + + // raw + + if (isLowCPixel || isHighCPixel) + zlibHasData(zis, 3 * t.area()); + else + zlibHasData(zis, sizeof(T) * t.area()); + + if (isLowCPixel || isHighCPixel) { + for (T* ptr = buf; ptr < buf+t.area(); ptr++) { + if (isLowCPixel) + *ptr = readOpaque24A(zis); + else + *ptr = readOpaque24B(zis); + } + } else { + zis->readBytes(buf, t.area() * sizeof(T)); + } + + } else { + + // packed pixels + int bppp = ((palSize > 16) ? 8 : + ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1))); + + T* ptr = buf; + + for (int i = 0; i < t.height(); i++) { + T* eol = ptr + t.width(); + rdr::U8 byte = 0; + rdr::U8 nbits = 0; + + while (ptr < eol) { + if (nbits == 0) { + zlibHasData(zis, 1); + byte = zis->readU8(); + nbits = 8; + } + nbits -= bppp; + rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127; + *ptr++ = palette[index]; + } + } } - if ((fitsInLS3Bytes && pf.isBigEndian()) || - (fitsInMS3Bytes && pf.isLittleEndian())) - { - zrleDecode24B(r, &is, &zis, pf, pb); - break; + } else { + + if (palSize == 0) { + + // plain RLE + + T* ptr = buf; + T* end = ptr + t.area(); + while (ptr < end) { + T pix; + if (isLowCPixel || isHighCPixel) + zlibHasData(zis, 3); + else + zlibHasData(zis, sizeof(T)); + if (isLowCPixel) + pix = readOpaque24A(zis); + else if (isHighCPixel) + pix = readOpaque24B(zis); + else + pix = readPixel<T>(zis); + int len = 1; + int b; + do { + zlibHasData(zis, 1); + b = zis->readU8(); + len += b; + } while (b == 255); + + if (end - ptr < len) { + throw Exception ("ZRLE decode error"); + } + + while (len-- > 0) *ptr++ = pix; + + } + } else { + + // palette RLE + + T* ptr = buf; + T* end = ptr + t.area(); + while (ptr < end) { + zlibHasData(zis, 1); + int index = zis->readU8(); + int len = 1; + if (index & 128) { + int b; + do { + zlibHasData(zis, 1); + b = zis->readU8(); + len += b; + } while (b == 255); + + if (end - ptr < len) { + throw Exception ("ZRLE decode error"); + } + } + + index &= 127; + + T pix = palette[index]; + + while (len-- > 0) *ptr++ = pix; + } } } - zrleDecode32(r, &is, &zis, pf, pb); - break; + pb->imageRect(pf, t, buf); } } + + zis->flushUnderlying(); + zis->setUnderlying(NULL, 0); } diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h index 115f8fb8..3885124a 100644 --- a/common/rfb/ZRLEDecoder.h +++ b/common/rfb/ZRLEDecoder.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +24,8 @@ namespace rfb { + class PixelFormat; + class ZRLEDecoder : public Decoder { public: ZRLEDecoder(); @@ -32,6 +35,13 @@ namespace rfb { virtual void decodeRect(const Rect& r, const void* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); + + private: + template<class T> + void zrleDecode(const Rect& r, rdr::InStream* is, + rdr::ZlibInStream* zis, + const PixelFormat& pf, ModifiablePixelBuffer* pb); + private: rdr::ZlibInStream zis; }; diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index 7d985401..d257d05c 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -239,16 +239,110 @@ void ZRLEEncoder::writePixels(const rdr::U8* buffer, const PixelFormat& pf, } } -// -// Including BPP-dependent implementation of the encoder. -// - -#define BPP 8 -#include <rfb/ZRLEEncoderBPP.cxx> -#undef BPP -#define BPP 16 -#include <rfb/ZRLEEncoderBPP.cxx> -#undef BPP -#define BPP 32 -#include <rfb/ZRLEEncoderBPP.cxx> -#undef BPP +template<class T> +void ZRLEEncoder::writePaletteTile(int width, int height, + const T* buffer, int stride, + const PixelFormat& pf, + const Palette& palette) +{ + const int bitsPerPackedPixel[] = { + 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + }; + + int bppp; + int pad; + + assert(palette.size() > 1); + assert(palette.size() <= 16); + + zos.writeU8(palette.size()); + writePalette(pf, palette); + + bppp = bitsPerPackedPixel[palette.size()-1]; + pad = stride - width; + + for (int i = 0; i < height; i++) { + int w; + + rdr::U8 nbits = 0; + rdr::U8 byte = 0; + + w = width; + while (w--) { + T pix = *buffer++; + rdr::U8 index = palette.lookup(pix); + byte = (byte << bppp) | index; + nbits += bppp; + if (nbits >= 8) { + zos.writeU8(byte); + nbits = 0; + } + } + if (nbits > 0) { + byte <<= 8 - nbits; + zos.writeU8(byte); + } + + buffer += pad; + } +} + +template<class T> +void ZRLEEncoder::writePaletteRLETile(int width, int height, + const T* buffer, int stride, + const PixelFormat& pf, + const Palette& palette) +{ + int pad; + + T prevColour; + int runLength; + + assert(palette.size() > 1); + assert(palette.size() <= 127); + + zos.writeU8(palette.size() | 0x80); + writePalette(pf, palette); + + pad = stride - width; + + prevColour = *buffer; + runLength = 0; + + while (height--) { + int w = width; + while (w--) { + if (prevColour != *buffer) { + if (runLength == 1) + zos.writeU8(palette.lookup(prevColour)); + else { + zos.writeU8(palette.lookup(prevColour) | 0x80); + + while (runLength > 255) { + zos.writeU8(255); + runLength -= 255; + } + zos.writeU8(runLength - 1); + } + + prevColour = *buffer; + runLength = 0; + } + + runLength++; + buffer++; + } + buffer += pad; + } + if (runLength == 1) + zos.writeU8(palette.lookup(prevColour)); + else { + zos.writeU8(palette.lookup(prevColour) | 0x80); + + while (runLength > 255) { + zos.writeU8(255); + runLength -= 255; + } + zos.writeU8(runLength - 1); + } +} diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h index 37a3be2d..a1f35533 100644 --- a/common/rfb/ZRLEEncoder.h +++ b/common/rfb/ZRLEEncoder.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2022 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,26 +50,14 @@ namespace rfb { unsigned int count); protected: - // Preprocessor generated, optimised methods - - void writePaletteTile(int width, int height, - const rdr::U8* buffer, int stride, - const PixelFormat& pf, const Palette& palette); - void writePaletteTile(int width, int height, - const rdr::U16* buffer, int stride, - const PixelFormat& pf, const Palette& palette); + // Templated, optimised methods + template<class T> void writePaletteTile(int width, int height, - const rdr::U32* buffer, int stride, + const T* buffer, int stride, const PixelFormat& pf, const Palette& palette); - - void writePaletteRLETile(int width, int height, - const rdr::U8* buffer, int stride, - const PixelFormat& pf, const Palette& palette); - void writePaletteRLETile(int width, int height, - const rdr::U16* buffer, int stride, - const PixelFormat& pf, const Palette& palette); + template<class T> void writePaletteRLETile(int width, int height, - const rdr::U32* buffer, int stride, + const T* buffer, int stride, const PixelFormat& pf, const Palette& palette); protected: diff --git a/common/rfb/ZRLEEncoderBPP.cxx b/common/rfb/ZRLEEncoderBPP.cxx deleted file mode 100644 index 90f395b3..00000000 --- a/common/rfb/ZRLEEncoderBPP.cxx +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) - -#define UBPP CONCAT2E(U,BPP) - -void ZRLEEncoder::writePaletteTile(int width, int height, - const rdr::UBPP* buffer, int stride, - const PixelFormat& pf, - const Palette& palette) -{ - const int bitsPerPackedPixel[] = { - 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - }; - - int bppp; - int pad; - - assert(palette.size() > 1); - assert(palette.size() <= 16); - - zos.writeU8(palette.size()); - writePalette(pf, palette); - - bppp = bitsPerPackedPixel[palette.size()-1]; - pad = stride - width; - - for (int i = 0; i < height; i++) { - int w; - - rdr::U8 nbits = 0; - rdr::U8 byte = 0; - - w = width; - while (w--) { - rdr::UBPP pix = *buffer++; - rdr::U8 index = palette.lookup(pix); - byte = (byte << bppp) | index; - nbits += bppp; - if (nbits >= 8) { - zos.writeU8(byte); - nbits = 0; - } - } - if (nbits > 0) { - byte <<= 8 - nbits; - zos.writeU8(byte); - } - - buffer += pad; - } -} - -void ZRLEEncoder::writePaletteRLETile(int width, int height, - const rdr::UBPP* buffer, int stride, - const PixelFormat& pf, - const Palette& palette) -{ - int pad; - - rdr::UBPP prevColour; - int runLength; - - assert(palette.size() > 1); - assert(palette.size() <= 127); - - zos.writeU8(palette.size() | 0x80); - writePalette(pf, palette); - - pad = stride - width; - - prevColour = *buffer; - runLength = 0; - - while (height--) { - int w = width; - while (w--) { - if (prevColour != *buffer) { - if (runLength == 1) - zos.writeU8(palette.lookup(prevColour)); - else { - zos.writeU8(palette.lookup(prevColour) | 0x80); - - while (runLength > 255) { - zos.writeU8(255); - runLength -= 255; - } - zos.writeU8(runLength - 1); - } - - prevColour = *buffer; - runLength = 0; - } - - runLength++; - buffer++; - } - buffer += pad; - } - if (runLength == 1) - zos.writeU8(palette.lookup(prevColour)); - else { - zos.writeU8(palette.lookup(prevColour) | 0x80); - - while (runLength > 255) { - zos.writeU8(255); - runLength -= 255; - } - zos.writeU8(runLength - 1); - } -} diff --git a/common/rfb/hextileDecode.h b/common/rfb/hextileDecode.h deleted file mode 100644 index 402cd031..00000000 --- a/common/rfb/hextileDecode.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// Hextile decoding function. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 - -#include <rdr/InStream.h> -#include <rfb/Exception.h> -#include <rfb/hextileConstants.h> - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL CONCAT2E(readOpaque,BPP) -#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP) - -static void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, - const PixelFormat& pf, - ModifiablePixelBuffer* pb) -{ - Rect t; - PIXEL_T bg = 0; - PIXEL_T fg = 0; - PIXEL_T buf[16 * 16]; - - for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { - - t.br.y = __rfbmin(r.br.y, t.tl.y + 16); - - for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) { - - t.br.x = __rfbmin(r.br.x, t.tl.x + 16); - - int tileType = is->readU8(); - - if (tileType & hextileRaw) { - is->readBytes(buf, t.area() * (BPP/8)); - pb->imageRect(pf, t, buf); - continue; - } - - if (tileType & hextileBgSpecified) - bg = is->READ_PIXEL(); - - int len = t.area(); - PIXEL_T* ptr = buf; - while (len-- > 0) *ptr++ = bg; - - if (tileType & hextileFgSpecified) - fg = is->READ_PIXEL(); - - if (tileType & hextileAnySubrects) { - int nSubrects = is->readU8(); - - for (int i = 0; i < nSubrects; i++) { - - if (tileType & hextileSubrectsColoured) - fg = is->READ_PIXEL(); - - int xy = is->readU8(); - int wh = is->readU8(); - - int x = ((xy >> 4) & 15); - int y = (xy & 15); - int w = ((wh >> 4) & 15) + 1; - int h = (wh & 15) + 1; - if (x + w > 16 || y + h > 16) { - throw rfb::Exception("HEXTILE_DECODE: Hextile out of bounds"); - } - PIXEL_T* ptr = buf + y * t.width() + x; - int rowAdd = t.width() - w; - while (h-- > 0) { - int len = w; - while (len-- > 0) *ptr++ = fg; - ptr += rowAdd; - } - } - } - pb->imageRect(pf, t, buf); - } - } -} - -#undef PIXEL_T -#undef READ_PIXEL -#undef HEXTILE_DECODE -} diff --git a/common/rfb/hextileEncode.h b/common/rfb/hextileEncode.h deleted file mode 100644 index aa5926cc..00000000 --- a/common/rfb/hextileEncode.h +++ /dev/null @@ -1,223 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Constantin Kaplinsky. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// Hextile encoding function. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 - -#include <rdr/OutStream.h> -#include <rfb/hextileConstants.h> - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP) -#define HEXTILE_ENCODE CONCAT2E(hextileEncode,BPP) -#define HEXTILE_ENCODE_TILE CONCAT2E(hextileEncodeTile,BPP) -#define TEST_TILE_TYPE CONCAT2E(hextileTestTileType,BPP) - -int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg); -int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType, - rdr::U8* encoded, PIXEL_T bg); - -void HEXTILE_ENCODE(rdr::OutStream* os, const PixelBuffer* pb) -{ - Rect t; - PIXEL_T buf[256]; - PIXEL_T oldBg = 0, oldFg = 0; - bool oldBgValid = false; - bool oldFgValid = false; - rdr::U8 encoded[256*(BPP/8)]; - - for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) { - - t.br.y = __rfbmin(pb->height(), t.tl.y + 16); - - for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) { - - t.br.x = __rfbmin(pb->width(), t.tl.x + 16); - - pb->getImage(buf, t); - - PIXEL_T bg = 0, fg = 0; - int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg); - - if (!oldBgValid || oldBg != bg) { - tileType |= hextileBgSpecified; - oldBg = bg; - oldBgValid = true; - } - - int encodedLen = 0; - - if (tileType & hextileAnySubrects) { - - if (tileType & hextileSubrectsColoured) { - oldFgValid = false; - } else { - if (!oldFgValid || oldFg != fg) { - tileType |= hextileFgSpecified; - oldFg = fg; - oldFgValid = true; - } - } - - encodedLen = HEXTILE_ENCODE_TILE(buf, t.width(), t.height(), tileType, - encoded, bg); - - if (encodedLen < 0) { - pb->getImage(buf, t); - os->writeU8(hextileRaw); - os->writeBytes(buf, t.width() * t.height() * (BPP/8)); - oldBgValid = oldFgValid = false; - continue; - } - } - - os->writeU8(tileType); - if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg); - if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg); - if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen); - } - } -} - - -int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType, - rdr::U8* encoded, PIXEL_T bg) -{ - rdr::U8* nSubrectsPtr = encoded; - *nSubrectsPtr = 0; - encoded++; - - for (int y = 0; y < h; y++) - { - int x = 0; - while (x < w) { - if (*data == bg) { - x++; - data++; - continue; - } - - // Find horizontal subrect first - PIXEL_T* ptr = data+1; - PIXEL_T* eol = data+w-x; - while (ptr < eol && *ptr == *data) ptr++; - int sw = ptr - data; - - ptr = data + w; - int sh = 1; - while (sh < h-y) { - eol = ptr + sw; - while (ptr < eol) - if (*ptr++ != *data) goto endOfSubrect; - ptr += w - sw; - sh++; - } - endOfSubrect: - - (*nSubrectsPtr)++; - - if (tileType & hextileSubrectsColoured) { - if (encoded - nSubrectsPtr + (BPP/8) > w*h*(BPP/8)) return -1; -#if (BPP == 8) - *encoded++ = *data; -#elif (BPP == 16) - *encoded++ = ((rdr::U8*)data)[0]; - *encoded++ = ((rdr::U8*)data)[1]; -#elif (BPP == 32) - *encoded++ = ((rdr::U8*)data)[0]; - *encoded++ = ((rdr::U8*)data)[1]; - *encoded++ = ((rdr::U8*)data)[2]; - *encoded++ = ((rdr::U8*)data)[3]; -#endif - } - - if (encoded - nSubrectsPtr + 2 > w*h*(BPP/8)) return -1; - *encoded++ = (x << 4) | y; - *encoded++ = ((sw-1) << 4) | (sh-1); - - ptr = data+w; - PIXEL_T* eor = data+w*sh; - while (ptr < eor) { - eol = ptr + sw; - while (ptr < eol) *ptr++ = bg; - ptr += w - sw; - } - x += sw; - data += sw; - } - } - return encoded - nSubrectsPtr; -} - - -int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg) -{ - PIXEL_T pix1 = *data; - PIXEL_T* end = data + w * h; - - PIXEL_T* ptr = data + 1; - while (ptr < end && *ptr == pix1) - ptr++; - - if (ptr == end) { - *bg = pix1; - return 0; // solid-color tile - } - - int count1 = ptr - data; - int count2 = 1; - PIXEL_T pix2 = *ptr++; - int tileType = hextileAnySubrects; - - for (; ptr < end; ptr++) { - if (*ptr == pix1) { - count1++; - } else if (*ptr == pix2) { - count2++; - } else { - tileType |= hextileSubrectsColoured; - break; - } - } - - if (count1 >= count2) { - *bg = pix1; *fg = pix2; - } else { - *bg = pix2; *fg = pix1; - } - return tileType; -} - -#undef PIXEL_T -#undef WRITE_PIXEL -#undef HEXTILE_ENCODE -#undef HEXTILE_ENCODE_TILE -#undef TEST_TILE_TYPE -} diff --git a/common/rfb/hextileEncodeBetter.h b/common/rfb/hextileEncodeBetter.h deleted file mode 100644 index bc9dcaca..00000000 --- a/common/rfb/hextileEncodeBetter.h +++ /dev/null @@ -1,346 +0,0 @@ -/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2005 Constantin Kaplinsky. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// Hextile encoding function. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 - -#include <rdr/OutStream.h> -#include <rfb/hextileConstants.h> -#include <rfb/Palette.h> - -#include <assert.h> - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP) -#define HEXTILE_TILE CONCAT2E(HextileTile,BPP) -#define HEXTILE_ENCODE CONCAT2E(hextileEncodeBetter,BPP) - -// -// This class analyzes a separate tile and encodes its subrectangles. -// - -class HEXTILE_TILE { - - public: - - HEXTILE_TILE (); - - // - // Initialize existing object instance with new tile data. - // - void newTile(const PIXEL_T *src, int w, int h); - - // - // Flags can include: hextileRaw, hextileAnySubrects and - // hextileSubrectsColoured. Note that if hextileRaw is set, other - // flags make no sense. Also, hextileSubrectsColoured is meaningful - // only when hextileAnySubrects is set as well. - // - int getFlags() const { return m_flags; } - - // - // Returns the size of encoded subrects data, including subrect count. - // The size is zero if flags do not include hextileAnySubrects. - // - int getSize() const { return m_size; } - - // - // Return optimal background. - // - int getBackground() const { return m_background; } - - // - // Return foreground if flags include hextileSubrectsColoured. - // - int getForeground() const { return m_foreground; } - - // - // Encode subrects. This function may be called only if - // hextileAnySubrects bit is set in flags. The buffer size should be - // big enough to store at least the number of bytes returned by the - // getSize() method. - // - void encode(rdr::U8* dst) const; - - protected: - - // - // Analyze the tile pixels, fill in all the data fields. - // - void analyze(); - - const PIXEL_T *m_tile; - int m_width; - int m_height; - - int m_size; - int m_flags; - PIXEL_T m_background; - PIXEL_T m_foreground; - - int m_numSubrects; - rdr::U8 m_coords[256 * 2]; - PIXEL_T m_colors[256]; - - private: - - bool m_processed[16][16]; - Palette m_pal; -}; - -HEXTILE_TILE::HEXTILE_TILE() - : m_tile(NULL), m_width(0), m_height(0), - m_size(0), m_flags(0), m_background(0), m_foreground(0), - m_numSubrects(0) -{ -} - -void HEXTILE_TILE::newTile(const PIXEL_T *src, int w, int h) -{ - m_tile = src; - m_width = w; - m_height = h; - - analyze(); -} - -void HEXTILE_TILE::analyze() -{ - assert(m_tile && m_width && m_height); - - const PIXEL_T *ptr = m_tile; - const PIXEL_T *end = &m_tile[m_width * m_height]; - PIXEL_T color = *ptr++; - while (ptr != end && *ptr == color) - ptr++; - - // Handle solid tile - if (ptr == end) { - m_background = m_tile[0]; - m_flags = 0; - m_size = 0; - return; - } - - // Compute number of complete rows of the same color, at the top - int y = (ptr - m_tile) / m_width; - - PIXEL_T *colorsPtr = m_colors; - rdr::U8 *coordsPtr = m_coords; - m_pal.clear(); - m_numSubrects = 0; - - // Have we found the first subrect already? - if (y > 0) { - *colorsPtr++ = color; - *coordsPtr++ = 0; - *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F)); - m_pal.insert(color, 1); - m_numSubrects++; - } - - memset(m_processed, 0, 16 * 16 * sizeof(bool)); - - int x, sx, sy, sw, sh, max_x; - - for (; y < m_height; y++) { - for (x = 0; x < m_width; x++) { - // Skip pixels that were processed earlier - if (m_processed[y][x]) { - continue; - } - // Determine dimensions of the horizontal subrect - color = m_tile[y * m_width + x]; - for (sx = x + 1; sx < m_width; sx++) { - if (m_tile[y * m_width + sx] != color) - break; - } - sw = sx - x; - max_x = sx; - for (sy = y + 1; sy < m_height; sy++) { - for (sx = x; sx < max_x; sx++) { - if (m_tile[sy * m_width + sx] != color) - goto done; - } - } - done: - sh = sy - y; - - // Save properties of this subrect - *colorsPtr++ = color; - *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F)); - *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F)); - - if (!m_pal.insert(color, 1) || (m_pal.size() > (48 + 2 * BPP))) { - // Handle palette overflow - m_flags = hextileRaw; - m_size = 0; - return; - } - - m_numSubrects++; - - // Mark pixels of this subrect as processed, below this row - for (sy = y + 1; sy < y + sh; sy++) { - for (sx = x; sx < x + sw; sx++) - m_processed[sy][sx] = true; - } - - // Skip processed pixels of this row - x += (sw - 1); - } - } - - // Save number of colors in this tile (should be no less than 2) - int numColors = m_pal.size(); - assert(numColors >= 2); - - m_background = (PIXEL_T)m_pal.getColour(0); - m_flags = hextileAnySubrects; - int numSubrects = m_numSubrects - m_pal.getCount(0); - - if (numColors == 2) { - // Monochrome tile - m_foreground = (PIXEL_T)m_pal.getColour(1); - m_size = 1 + 2 * numSubrects; - } else { - // Colored tile - m_flags |= hextileSubrectsColoured; - m_size = 1 + (2 + (BPP/8)) * numSubrects; - } -} - -void HEXTILE_TILE::encode(rdr::U8 *dst) const -{ - assert(m_numSubrects && (m_flags & hextileAnySubrects)); - - // Zero subrects counter - rdr::U8 *numSubrectsPtr = dst; - *dst++ = 0; - - for (int i = 0; i < m_numSubrects; i++) { - if (m_colors[i] == m_background) - continue; - - if (m_flags & hextileSubrectsColoured) { -#if (BPP == 8) - *dst++ = m_colors[i]; -#elif (BPP == 16) - *dst++ = ((rdr::U8*)&m_colors[i])[0]; - *dst++ = ((rdr::U8*)&m_colors[i])[1]; -#elif (BPP == 32) - *dst++ = ((rdr::U8*)&m_colors[i])[0]; - *dst++ = ((rdr::U8*)&m_colors[i])[1]; - *dst++ = ((rdr::U8*)&m_colors[i])[2]; - *dst++ = ((rdr::U8*)&m_colors[i])[3]; -#endif - } - *dst++ = m_coords[i * 2]; - *dst++ = m_coords[i * 2 + 1]; - - (*numSubrectsPtr)++; - } - - assert(dst - numSubrectsPtr == m_size); -} - -// -// Main encoding function. -// - -void HEXTILE_ENCODE(rdr::OutStream* os, const PixelBuffer* pb) -{ - Rect t; - PIXEL_T buf[256]; - PIXEL_T oldBg = 0, oldFg = 0; - bool oldBgValid = false; - bool oldFgValid = false; - rdr::U8 encoded[256*(BPP/8)]; - - HEXTILE_TILE tile; - - for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) { - - t.br.y = __rfbmin(pb->height(), t.tl.y + 16); - - for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) { - - t.br.x = __rfbmin(pb->width(), t.tl.x + 16); - - pb->getImage(buf, t); - - tile.newTile(buf, t.width(), t.height()); - int tileType = tile.getFlags(); - int encodedLen = tile.getSize(); - - if ( (tileType & hextileRaw) != 0 || - encodedLen >= t.width() * t.height() * (BPP/8)) { - os->writeU8(hextileRaw); - os->writeBytes(buf, t.width() * t.height() * (BPP/8)); - oldBgValid = oldFgValid = false; - continue; - } - - PIXEL_T bg = tile.getBackground(); - PIXEL_T fg = 0; - - if (!oldBgValid || oldBg != bg) { - tileType |= hextileBgSpecified; - oldBg = bg; - oldBgValid = true; - } - - if (tileType & hextileAnySubrects) { - if (tileType & hextileSubrectsColoured) { - oldFgValid = false; - } else { - fg = tile.getForeground(); - if (!oldFgValid || oldFg != fg) { - tileType |= hextileFgSpecified; - oldFg = fg; - oldFgValid = true; - } - } - tile.encode(encoded); - } - - os->writeU8(tileType); - if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg); - if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg); - if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen); - } - } -} - -#undef PIXEL_T -#undef WRITE_PIXEL -#undef HEXTILE_TILE -#undef HEXTILE_ENCODE -} diff --git a/common/rfb/rreDecode.h b/common/rfb/rreDecode.h deleted file mode 100644 index f9fdcfc9..00000000 --- a/common/rfb/rreDecode.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// RRE decoding function. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 - -#include <rdr/InStream.h> -#include <rfb/Exception.h> - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL CONCAT2E(readOpaque,BPP) -#define RRE_DECODE CONCAT2E(rreDecode,BPP) - -void RRE_DECODE (const Rect& r, rdr::InStream* is, - const PixelFormat& pf, ModifiablePixelBuffer* pb) -{ - int nSubrects = is->readU32(); - PIXEL_T bg = is->READ_PIXEL(); - pb->fillRect(pf, r, &bg); - - for (int i = 0; i < nSubrects; i++) { - PIXEL_T pix = is->READ_PIXEL(); - int x = is->readU16(); - int y = is->readU16(); - int w = is->readU16(); - int h = is->readU16(); - - if (((x+w) > r.width()) || ((y+h) > r.height())) - throw Exception ("RRE decode error"); - - pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), &pix); - } -} - -#undef PIXEL_T -#undef READ_PIXEL -#undef RRE_DECODE -} diff --git a/common/rfb/rreEncode.h b/common/rfb/rreEncode.h deleted file mode 100644 index c8bbee7a..00000000 --- a/common/rfb/rreEncode.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// RRE encoding function. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 -// -// The data argument to RRE_ENCODE contains the pixel data, and it writes the -// encoded version to the given OutStream. If the encoded version exceeds w*h -// it aborts and returns -1, otherwise it returns the number of subrectangles. -// - -#include <rdr/OutStream.h> - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP) -#define RRE_ENCODE CONCAT2E(rreEncode,BPP) - -int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg) -{ - os->WRITE_PIXEL(bg); - - int nSubrects = 0; - - for (int y = 0; y < h; y++) - { - int x = 0; - while (x < w) { - if (*data == bg) { - x++; - data++; - continue; - } - - // Find horizontal subrect first - PIXEL_T* ptr = data+1; - PIXEL_T* eol = data+w-x; - while (ptr < eol && *ptr == *data) ptr++; - int sw = ptr - data; - - ptr = data + w; - int sh = 1; - while (sh < h-y) { - eol = ptr + sw; - while (ptr < eol) - if (*ptr++ != *data) goto endOfHorizSubrect; - ptr += w - sw; - sh++; - } - endOfHorizSubrect: - - // Find vertical subrect - int vh; - for (vh = sh; vh < h-y; vh++) - if (data[vh*w] != *data) break; - - if (vh != sh) { - ptr = data+1; - int vw; - for (vw = 1; vw < sw; vw++) { - for (int i = 0; i < vh; i++) - if (ptr[i*w] != *data) goto endOfVertSubrect; - ptr++; - } - endOfVertSubrect: - - // If vertical subrect bigger than horizontal then use that. - if (sw*sh < vw*vh) { - sw = vw; - sh = vh; - } - } - - nSubrects++; - os->WRITE_PIXEL(*data); - os->writeU16(x); - os->writeU16(y); - os->writeU16(sw); - os->writeU16(sh); - - ptr = data+w; - PIXEL_T* eor = data+w*sh; - while (ptr < eor) { - eol = ptr + sw; - while (ptr < eol) *ptr++ = bg; - ptr += w - sw; - } - x += sw; - data += sw; - } - } - - return nSubrects; -} - -#undef PIXEL_T -#undef WRITE_PIXEL -#undef RRE_ENCODE -} diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h deleted file mode 100644 index 8f77aebd..00000000 --- a/common/rfb/tightDecode.h +++ /dev/null @@ -1,187 +0,0 @@ -/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. - * Copyright 2004-2005 Cendio AB. - * Copyright 2009-2015 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -// Tight decoding functions. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#define PIXEL_T rdr::CONCAT2E(U,BPP) - -#if BPP == 32 - -void -TightDecoder::FilterGradient24(const rdr::U8 *inbuf, - const PixelFormat& pf, PIXEL_T* outbuf, - int stride, const Rect& r) -{ - int x, y, c; - rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; - rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; - rdr::U8 pix[3]; - int est[3]; - - memset(prevRow, 0, sizeof(prevRow)); - - // Set up shortcut variables - int rectHeight = r.height(); - int rectWidth = r.width(); - - for (y = 0; y < rectHeight; y++) { - for (x = 0; x < rectWidth; x++) { - /* First pixel in a row */ - if (x == 0) { - for (c = 0; c < 3; c++) { - pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c]; - thisRow[c] = pix[c]; - } - pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); - continue; - } - - for (c = 0; c < 3; c++) { - est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c]; - if (est[c] > 0xff) { - est[c] = 0xff; - } else if (est[c] < 0) { - est[c] = 0; - } - pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c]; - thisRow[x*3+c] = pix[c]; - } - pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); - } - - memcpy(prevRow, thisRow, sizeof(prevRow)); - } -} - -#endif - -#if BPP != 8 - -void TightDecoder::FilterGradient(const rdr::U8* inbuf, - const PixelFormat& pf, PIXEL_T* outbuf, - int stride, const Rect& r) -{ - int x, y, c; - static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; - static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; - rdr::U8 pix[3]; - int est[3]; - - memset(prevRow, 0, sizeof(prevRow)); - - // Set up shortcut variables - int rectHeight = r.height(); - int rectWidth = r.width(); - - for (y = 0; y < rectHeight; y++) { - for (x = 0; x < rectWidth; x++) { - /* First pixel in a row */ - if (x == 0) { - pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1); - for (c = 0; c < 3; c++) - pix[c] += prevRow[c]; - - memcpy(thisRow, pix, sizeof(pix)); - - pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); - - continue; - } - - for (c = 0; c < 3; c++) { - est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c]; - if (est[c] > 255) { - est[c] = 255; - } else if (est[c] < 0) { - est[c] = 0; - } - } - - pf.rgbFromBuffer(pix, &inbuf[y*rectWidth+x], 1); - for (c = 0; c < 3; c++) - pix[c] += est[c]; - - memcpy(&thisRow[x*3], pix, sizeof(pix)); - - pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); - } - - memcpy(prevRow, thisRow, sizeof(prevRow)); - } -} - -#endif - -void TightDecoder::FilterPalette(const PIXEL_T* palette, int palSize, - const rdr::U8* inbuf, PIXEL_T* outbuf, - int stride, const Rect& r) -{ - // Indexed color - int x, h = r.height(), w = r.width(), b, pad = stride - w; - PIXEL_T* ptr = outbuf; - rdr::U8 bits; - const rdr::U8* srcPtr = inbuf; - if (palSize <= 2) { - // 2-color palette - while (h > 0) { - for (x = 0; x < w / 8; x++) { - bits = *srcPtr++; - for (b = 7; b >= 0; b--) { - *ptr++ = palette[bits >> b & 1]; - } - } - if (w % 8 != 0) { - bits = *srcPtr++; - for (b = 7; b >= 8 - w % 8; b--) { - *ptr++ = palette[bits >> b & 1]; - } - } - ptr += pad; - h--; - } - } else { - // 256-color palette - while (h > 0) { - PIXEL_T *endOfRow = ptr + w; - while (ptr < endOfRow) { - *ptr++ = palette[*srcPtr++]; - } - ptr += pad; - h--; - } - } -} - -#undef PIXEL_T -} diff --git a/common/rfb/zrleDecode.h b/common/rfb/zrleDecode.h deleted file mode 100644 index 998e51ed..00000000 --- a/common/rfb/zrleDecode.h +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -// ZRLE decoding function. -// -// This file is #included after having set the following macro: -// BPP - 8, 16 or 32 - -namespace rfb { - -// CONCAT2E concatenates its arguments, expanding them if they are macros - -#ifndef CONCAT2E -#define CONCAT2(a,b) a##b -#define CONCAT2E(a,b) CONCAT2(a,b) -#endif - -#ifdef CPIXEL -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL(is) CONCAT2E(readOpaque,CPIXEL)(is) -#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL) -#else -#define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL(is) is->CONCAT2E(readOpaque,BPP)() -#define ZRLE_DECODE CONCAT2E(zrleDecode,BPP) -#endif - -void ZRLE_DECODE (const Rect& r, rdr::InStream* is, - rdr::ZlibInStream* zis, - const PixelFormat& pf, ModifiablePixelBuffer* pb) -{ - int length = is->readU32(); - zis->setUnderlying(is, length); - Rect t; - PIXEL_T buf[64 * 64]; - - for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) { - - t.br.y = __rfbmin(r.br.y, t.tl.y + 64); - - for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) { - - t.br.x = __rfbmin(r.br.x, t.tl.x + 64); - - zlibHasData(zis, 1); - int mode = zis->readU8(); - bool rle = mode & 128; - int palSize = mode & 127; - PIXEL_T palette[128]; - -#ifdef CPIXEL - zlibHasData(zis, 3 * palSize); -#else - zlibHasData(zis, BPP/8 * palSize); -#endif - for (int i = 0; i < palSize; i++) { - palette[i] = READ_PIXEL(zis); - } - - if (palSize == 1) { - PIXEL_T pix = palette[0]; - pb->fillRect(pf, t, &pix); - continue; - } - - if (!rle) { - if (palSize == 0) { - - // raw - -#ifdef CPIXEL - zlibHasData(zis, 3 * t.area()); - for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) { - *ptr = READ_PIXEL(zis); - } -#else - zlibHasData(zis, BPP/8 * t.area()); - zis->readBytes(buf, t.area() * (BPP / 8)); -#endif - - } else { - - // packed pixels - int bppp = ((palSize > 16) ? 8 : - ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1))); - - PIXEL_T* ptr = buf; - - for (int i = 0; i < t.height(); i++) { - PIXEL_T* eol = ptr + t.width(); - rdr::U8 byte = 0; - rdr::U8 nbits = 0; - - while (ptr < eol) { - if (nbits == 0) { - zlibHasData(zis, 1); - byte = zis->readU8(); - nbits = 8; - } - nbits -= bppp; - rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127; - *ptr++ = palette[index]; - } - } - } - - } else { - - if (palSize == 0) { - - // plain RLE - - PIXEL_T* ptr = buf; - PIXEL_T* end = ptr + t.area(); - while (ptr < end) { -#ifdef CPIXEL - zlibHasData(zis, 3); -#else - zlibHasData(zis, BPP/8); -#endif - PIXEL_T pix = READ_PIXEL(zis); - int len = 1; - int b; - do { - zlibHasData(zis, 1); - b = zis->readU8(); - len += b; - } while (b == 255); - - if (end - ptr < len) { - throw Exception ("ZRLE decode error"); - } - - while (len-- > 0) *ptr++ = pix; - - } - } else { - - // palette RLE - - PIXEL_T* ptr = buf; - PIXEL_T* end = ptr + t.area(); - while (ptr < end) { - zlibHasData(zis, 1); - int index = zis->readU8(); - int len = 1; - if (index & 128) { - int b; - do { - zlibHasData(zis, 1); - b = zis->readU8(); - len += b; - } while (b == 255); - - if (end - ptr < len) { - throw Exception ("ZRLE decode error"); - } - } - - index &= 127; - - PIXEL_T pix = palette[index]; - - while (len-- > 0) *ptr++ = pix; - } - } - } - - pb->imageRect(pf, t, buf); - } - } - - zis->flushUnderlying(); - zis->setUnderlying(NULL, 0); -} - -#undef ZRLE_DECODE -#undef READ_PIXEL -#undef PIXEL_T -} |