From: Pierre Ossman Date: Sat, 10 Sep 2022 11:48:53 +0000 (+0200) Subject: Use templates for optimized code X-Git-Tag: v1.13.90~87^2~34 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=baca73d03217a1c219d9c4f024ffcd39f85fd322;p=tigervnc.git Use templates for optimized code Avoid preprocessor magic and instead rely on templating to generate optimized functions for performance critical code. --- 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 +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 +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 + 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 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 #include +#include #include #include #include +#include using namespace rfb; -#define BPP 8 -#include -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#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(r, &is, pf, pb); break; + case 16: hextileDecode(r, &is, pf, pb); break; + case 32: hextileDecode(r, &is, pf, pb); break; + } +} + +template +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 +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(is); + + int len = t.area(); + T* ptr = buf; + while (len-- > 0) *ptr++ = bg; + + if (tileType & hextileFgSpecified) + fg = readPixel(is); + + if (tileType & hextileAnySubrects) { + int nSubrects = is->readU8(); + + for (int i = 0; i < nSubrects; i++) { + + if (tileType & hextileSubrectsColoured) + fg = readPixel(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 + inline T readPixel(rdr::InStream* is); + template + 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 #include #include +#include #include #include +#include using namespace rfb; @@ -36,19 +38,6 @@ BoolParameter improvedHextile("ImprovedHextile", "ratios by the cost of using more CPU time", true); -#define BPP 8 -#include -#include -#undef BPP -#define BPP 16 -#include -#include -#undef BPP -#define BPP 32 -#include -#include -#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(os, pb); } else { - hextileEncode8(os, pb); + hextileEncode(os, pb); } break; case 16: if (improvedHextile) { - hextileEncodeBetter16(os, pb); + hextileEncodeBetter(os, pb); } else { - hextileEncode16(os, pb); + hextileEncode(os, pb); } break; case 32: if (improvedHextile) { - hextileEncodeBetter32(os, pb); + hextileEncodeBetter(os, pb); } else { - hextileEncode32(os, pb); + hextileEncode(os, pb); } break; } @@ -110,3 +99,496 @@ void HextileEncoder::writeSolidRect(int width, int height, while (tiles--) os->writeU8(0); } + +template +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 +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 +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 +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 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 +HextileTile::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 +void HextileTile::newTile(const T *src, int w, int h) +{ + m_tile = src; + m_width = w; + m_height = h; + + analyze(); +} + +template +void HextileTile::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 +void HextileTile::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 +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 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 + inline void writePixel(rdr::OutStream* os, T pixel); + + template + void hextileEncode(rdr::OutStream* os, const PixelBuffer* pb); + template + int hextileEncodeTile(T* data, int w, int h, int tileType, + rdr::U8* encoded, T bg); + template + int testTileType(T* data, int w, int h, T* bg, T* fg); + + template + 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 +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 +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 + 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 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 #include +#include #include #include #include using namespace rfb; -#define BPP 8 -#include -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#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(r, &is, pf, pb); break; + case 16: rreDecode(r, &is, pf, pb); break; + case 32: rreDecode(r, &is, pf, pb); break; + } +} + +template +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 +void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is, + const PixelFormat& pf, + ModifiablePixelBuffer* pb) +{ + int nSubrects = is->readU32(); + T bg = readPixel(is); + pb->fillRect(pf, r, &bg); + + for (int i = 0; i < nSubrects; i++) { + T pix = readPixel(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 + inline T readPixel(rdr::InStream* is); + template + 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 -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#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*)imageBuf, w, h, &mos, bg); break; case 16: - nSubrects = rreEncode16((rdr::U16*)imageBuf, w, h, &mos, bg); + nSubrects = rreEncode((rdr::U16*)imageBuf, w, h, &mos, bg); break; case 32: - nSubrects = rreEncode32((rdr::U32*)imageBuf, w, h, &mos, bg); + nSubrects = rreEncode((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 +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 +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 @@ -34,6 +34,11 @@ namespace rfb { virtual void writeSolidRect(int width, int height, const PixelFormat& pf, const rdr::U8* colour); + private: + template + inline void writePixel(rdr::OutStream* os, T pixel); + template + 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 -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#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 +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 +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 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 + 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 +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 -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#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 +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 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 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 +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 -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#define CPIXEL 24A -#include -#undef CPIXEL -#define CPIXEL 24B -#include -#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(r, &is, &zis, pf, pb); break; + case 16: zrleDecode(r, &is, &zis, pf, pb); break; + case 32: zrleDecode(r, &is, &zis, pf, pb); break; + } +} + +template +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(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(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 + 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 -#undef BPP -#define BPP 16 -#include -#undef BPP -#define BPP 32 -#include -#undef BPP +template +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 +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 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 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 -#include -#include - -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 -#include - -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 -#include -#include - -#include - -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 -#include - -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 - -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 -}