From 33c15e3a3a1db376feae90ef7521a107dd957752 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 3 Nov 2011 18:49:21 +0000 Subject: [PATCH] If the client and server are using identical pixel formats, then perform Tight decoding directly into the viewer's back buffer, rather than going through the slow fillRect/imageRect routines. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4757 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- common/rfb/CMakeLists.txt | 1 + common/rfb/CMsgHandler.h | 6 + common/rfb/PixelFormat.cxx | 55 +++++++ common/rfb/PixelFormat.h | 2 + common/rfb/TightDecoder.cxx | 100 +++---------- common/rfb/TightDecoder.h | 32 +++++ common/rfb/tightDecode.h | 276 +++++++++++++++--------------------- vncviewer/CConn.cxx | 9 ++ vncviewer/CConn.h | 5 + vncviewer/DesktopWindow.h | 7 + vncviewer/Viewport.h | 16 ++- 11 files changed, 263 insertions(+), 246 deletions(-) diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt index be03c646..27e3caa5 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -23,6 +23,7 @@ set(RFB_SOURCES HextileDecoder.cxx HextileEncoder.cxx JpegCompressor.cxx + JpegDecompressor.cxx KeyRemapper.cxx LogWriter.cxx Logger.cxx diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index d8b949b3..c81d55ef 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2009 Pierre Ossman for Cendio AB + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,6 +69,11 @@ namespace rfb { virtual void imageRect(const Rect& r, void* pixels) = 0; virtual void copyRect(const Rect& r, int srcX, int srcY) = 0; + virtual rdr::U8* getRawPixelsRW(const Rect& r, int* stride) = 0; + virtual void releaseRawPixels(const Rect& r) = 0; + + virtual const PixelFormat &getPreferredPF(void) = 0; + ConnParams cp; }; } diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index c5bec825..f7073224 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -225,6 +225,61 @@ void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, } +void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, + int w, int pitch, int h, ColourMap* cm) const +{ + if (is888()) { + // Optimised common case + int rindex, gindex, bindex; + + if (bigEndian) { + rindex = (24 - redShift)/8; + gindex = (24 - greenShift)/8; + bindex = (24 - blueShift)/8; + } else { + rindex = redShift/8; + gindex = greenShift/8; + bindex = blueShift/8; + } + + int dstPad = pitch - w * 4; + while (h > 0) { + rdr::U8 *dstEndOfRow = (rdr::U8 *)dst + w * 4; + while (dst < dstEndOfRow) { + dst[rindex] = *(src++); + dst[gindex] = *(src++); + dst[bindex] = *(src++); + dst += 4; + } + dst += dstPad; + h--; + } + } else { + // Generic code + Pixel p; + rdr::U8 r, g, b; + int pixelSize = bpp/8; + + int dstPad = pitch - w * pixelSize; + while (h > 0) { + rdr::U8 *dstEndOfRow = (rdr::U8 *)dst + w * pixelSize; + while (dst < dstEndOfRow) { + r = *(src++); + g = *(src++); + b = *(src++); + + p = pixelFromRGB(r, g, b, cm); + + bufferFromPixel(dst, p); + dst += pixelSize; + } + dst += dstPad; + h--; + } + } +} + + void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, Colour* rgb) const { rdr::U16 r, g, b; diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h index 6566e38b..88e80f4c 100644 --- a/common/rfb/PixelFormat.h +++ b/common/rfb/PixelFormat.h @@ -53,6 +53,8 @@ namespace rfb { Pixel pixelFromRGB(rdr::U8 red, rdr::U8 green, rdr::U8 blue, ColourMap* cm=0) const; void bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const; + void bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int w, int pitch, + int h, ColourMap* cm=0) const; void rgbFromPixel(Pixel pix, ColourMap* cm, Colour* rgb) const; inline void rgbFromPixel(Pixel pix, ColourMap* cm, rdr::U16 *r, rdr::U16 *g, rdr::U16 *b) const; diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index daca00aa..670e480a 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -1,5 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright 2004-2005 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 @@ -19,19 +20,11 @@ #include #include #include -#include /* jpeglib.h needs FILE */ -extern "C" { -#include -} using namespace rfb; #define TIGHT_MAX_WIDTH 2048 -static void JpegSetSrcManager(j_decompress_ptr cinfo, char *compressedData, - int compressedLen); -static bool jpegError; - #define EXTRA_ARGS CMsgHandler* handler #define FILL_RECT(r, p) handler->fillRect(r, p) #define IMAGE_RECT(r, p) handler->imageRect(r, p) @@ -60,82 +53,25 @@ TightDecoder::~TightDecoder() void TightDecoder::readRect(const Rect& r, CMsgHandler* handler) { - rdr::InStream* is = reader->getInStream(); - /* Uncompressed RGB24 JPEG data, before translated, can be up to 3 - times larger, if VNC bpp is 8. */ - rdr::U8* buf = reader->getImageBuf(r.area()*3); - switch (reader->bpp()) { + is = reader->getInStream(); + this->handler = handler; + clientpf = handler->getPreferredPF(); + serverpf = handler->cp.pf(); + + if (clientpf.equal(serverpf)) { + /* Decode directly into the framebuffer (fast path) */ + directDecode = true; + } else { + /* Decode into an intermediate buffer and use pixel translation */ + directDecode = false; + } + + switch (serverpf.bpp) { case 8: - tightDecode8 (r, is, zis, (rdr::U8*) buf, handler); break; + tightDecode8 (r); break; case 16: - tightDecode16(r, is, zis, (rdr::U16*)buf, handler); break; + tightDecode16(r); break; case 32: - tightDecode32(r, is, zis, (rdr::U32*)buf, handler); break; + tightDecode32(r); break; } } - - -// -// A "Source manager" for the JPEG library. -// - -static struct jpeg_source_mgr jpegSrcManager; -static JOCTET *jpegBufferPtr; -static size_t jpegBufferLen; - -static void JpegInitSource(j_decompress_ptr cinfo); -static boolean JpegFillInputBuffer(j_decompress_ptr cinfo); -static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes); -static void JpegTermSource(j_decompress_ptr cinfo); - -static void -JpegInitSource(j_decompress_ptr cinfo) -{ - jpegError = false; -} - -static boolean -JpegFillInputBuffer(j_decompress_ptr cinfo) -{ - jpegError = true; - jpegSrcManager.bytes_in_buffer = jpegBufferLen; - jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; - - return TRUE; -} - -static void -JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes) -{ - if (num_bytes < 0 || (size_t)num_bytes > jpegSrcManager.bytes_in_buffer) { - jpegError = true; - jpegSrcManager.bytes_in_buffer = jpegBufferLen; - jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; - } else { - jpegSrcManager.next_input_byte += (size_t) num_bytes; - jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes; - } -} - -static void -JpegTermSource(j_decompress_ptr cinfo) -{ - /* No work necessary here. */ -} - -static void -JpegSetSrcManager(j_decompress_ptr cinfo, char *compressedData, int compressedLen) -{ - jpegBufferPtr = (JOCTET *)compressedData; - jpegBufferLen = (size_t)compressedLen; - - jpegSrcManager.init_source = JpegInitSource; - jpegSrcManager.fill_input_buffer = JpegFillInputBuffer; - jpegSrcManager.skip_input_data = JpegSkipInputData; - jpegSrcManager.resync_to_restart = jpeg_resync_to_restart; - jpegSrcManager.term_source = JpegTermSource; - jpegSrcManager.next_input_byte = jpegBufferPtr; - jpegSrcManager.bytes_in_buffer = jpegBufferLen; - - cinfo->src = &jpegSrcManager; -} diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h index 1047b374..9a28fb9b 100644 --- a/common/rfb/TightDecoder.h +++ b/common/rfb/TightDecoder.h @@ -1,4 +1,5 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,18 +21,49 @@ #include #include +#include namespace rfb { class TightDecoder : public Decoder { + public: static Decoder* create(CMsgReader* reader); virtual void readRect(const Rect& r, CMsgHandler* handler); virtual ~TightDecoder(); + private: + void tightDecode8(const Rect& r); + void tightDecode16(const Rect& r); + void tightDecode32(const Rect& r); + + void DecompressJpegRect8(const Rect& r); + void DecompressJpegRect16(const Rect& r); + void DecompressJpegRect32(const Rect& r); + + void FilterGradient8(rdr::InStream* is, rdr::U8* buf, int stride, + const Rect& r, int dataSize); + void FilterGradient16(rdr::InStream* is, rdr::U16* buf, int stride, + const Rect& r, int dataSize); + void FilterGradient24(rdr::InStream* is, rdr::U32* buf, int stride, + const Rect& r, int dataSize); + void FilterGradient32(rdr::InStream* is, rdr::U32* buf, int stride, + const Rect& r, int dataSize); + + void directFillRect8(const Rect& r, Pixel pix); + void directFillRect16(const Rect& r, Pixel pix); + void directFillRect32(const Rect& r, Pixel pix); + TightDecoder(CMsgReader* reader); + CMsgReader* reader; + CMsgHandler* handler; + rdr::InStream* is; rdr::ZlibInStream zis[4]; + JpegDecompressor jd; + PixelFormat clientpf; + PixelFormat serverpf; + bool directDecode; }; // Compression control diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h index 96042cb8..4ea18a97 100644 --- a/common/rfb/tightDecode.h +++ b/common/rfb/tightDecode.h @@ -1,5 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright 2004-2005 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 @@ -42,32 +43,20 @@ namespace rfb { #define PIXEL_T rdr::CONCAT2E(U,BPP) #define READ_PIXEL CONCAT2E(readOpaque,BPP) -#define TIGHT_DECODE CONCAT2E(tightDecode,BPP) +#define TIGHT_DECODE TightDecoder::CONCAT2E(tightDecode,BPP) +#define DECOMPRESS_JPEG_RECT TightDecoder::CONCAT2E(DecompressJpegRect,BPP) +#define FILTER_GRADIENT TightDecoder::CONCAT2E(FilterGradient,BPP) +#define DIRECT_FILL_RECT TightDecoder::CONCAT2E(directFillRect,BPP) #define TIGHT_MIN_TO_COMPRESS 12 -static bool DecompressJpegRect(const Rect& r, rdr::InStream* is, - PIXEL_T* buf, CMsgHandler* handler); -static void FilterGradient(const Rect& r, rdr::InStream* is, int dataSize, - PIXEL_T* buf, CMsgHandler* handler); -#if BPP == 32 -static void FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize, - PIXEL_T* buf, CMsgHandler* handler); -#endif // Main function implementing Tight decoder -void TIGHT_DECODE (const Rect& r, rdr::InStream* is, - rdr::ZlibInStream zis[], PIXEL_T* buf -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) +void TIGHT_DECODE (const Rect& r) { - rdr::U8 *bytebuf = (rdr::U8*) buf; bool cutZeros = false; - const rfb::PixelFormat& myFormat = handler->cp.pf(); #if BPP == 32 - if (myFormat.is888()) { + if (serverpf.is888()) { cutZeros = true; } #endif @@ -86,18 +75,20 @@ void TIGHT_DECODE (const Rect& r, rdr::InStream* is, if (comp_ctl == rfbTightFill) { PIXEL_T pix; if (cutZeros) { + rdr::U8 bytebuf[3]; is->readBytes(bytebuf, 3); - myFormat.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1, NULL); } else { pix = is->READ_PIXEL(); } - FILL_RECT(r, pix); + if (directDecode) DIRECT_FILL_RECT(r, pix); + else FILL_RECT(r, pix); return; } // "JPEG" compression type. if (comp_ctl == rfbTightJpeg) { - DecompressJpegRect(r, is, buf, handler); + DECOMPRESS_JPEG_RECT(r); return; } @@ -122,11 +113,11 @@ void TIGHT_DECODE (const Rect& r, rdr::InStream* is, rdr::U8 elem[3]; for (int i = 0;i < palSize;i++) { is->readBytes(elem, 3); - myFormat.bufferFromRGB((rdr::U8*)&palette[i], elem, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&palette[i], elem, 1, NULL); } } else { - for (int i = 0; i < palSize; i++) - palette[i] = is->READ_PIXEL(); + for (int i = 0; i < palSize; i++) + palette[i] = is->READ_PIXEL(); } break; case rfbTightFilterGradient: @@ -161,78 +152,93 @@ void TIGHT_DECODE (const Rect& r, rdr::InStream* is, input = &zis[streamId]; } + PIXEL_T *buf; + int stride = r.width(); + if (directDecode) buf = (PIXEL_T *)handler->getRawPixelsRW(r, &stride); + else buf = (PIXEL_T *)reader->getImageBuf(r.area()); + if (palSize == 0) { // Truecolor data if (useGradient) { #if BPP == 32 if (cutZeros) { - FilterGradient24(r, input, dataSize, buf, handler); + FilterGradient24(input, buf, stride, r, dataSize); } else #endif - { - FilterGradient(r, input, dataSize, buf, handler); - } + { + FILTER_GRADIENT(input, buf, stride, r, dataSize); + } } else { + // Copy + int h = r.height(); + PIXEL_T *ptr = buf; if (cutZeros) { + int w = r.width(), pad = stride - w; rdr::U8 elem[3]; - for (int i = 0;i < r.area();i++) { - input->readBytes(elem, 3); - myFormat.bufferFromRGB((rdr::U8*)&buf[i], elem, 1, NULL); + while (h > 0) { + PIXEL_T *endOfRow = ptr + w; + while (ptr < endOfRow) { + input->readBytes(elem, 3); + serverpf.bufferFromRGB((rdr::U8*)ptr++, elem, 1, NULL); + } + ptr += pad; + h--; } } else { - input->readBytes(buf, dataSize); + while (h > 0) { + input->readBytes(ptr, rowSize); + ptr += stride; + h--; + } } } } else { - int x, y, b; + // Indexed color + int x, h = r.height(), w = r.width(), b, pad = stride - w; PIXEL_T *ptr = buf; rdr::U8 bits; if (palSize <= 2) { // 2-color palette - for (y = 0; y < r.height(); y++) { - for (x = 0; x < r.width() / 8; x++) { + while (h > 0) { + for (x = 0; x < w / 8; x++) { bits = input->readU8(); for (b = 7; b >= 0; b--) { *ptr++ = palette[bits >> b & 1]; - } + } } - if (r.width() % 8 != 0) { + if (w % 8 != 0) { bits = input->readU8(); - for (b = 7; b >= 8 - r.width() % 8; b--) { + for (b = 7; b >= 8 - w % 8; b--) { *ptr++ = palette[bits >> b & 1]; } } + ptr += pad; + h--; } } else { // 256-color palette - for (y = 0; y < r.height(); y++) { - for (x = 0; x < r.width(); x++) { + while (h > 0) { + PIXEL_T *endOfRow = ptr + w; + while (ptr < endOfRow) { *ptr++ = palette[input->readU8()]; - } + } + ptr += pad; + h--; } } } - IMAGE_RECT(r, buf); + if (directDecode) handler->releaseRawPixels(r); + else IMAGE_RECT(r, buf); if (streamId != -1) { zis[streamId].reset(); } } -static bool -DecompressJpegRect(const Rect& r, rdr::InStream* is, - PIXEL_T* buf, CMsgHandler* handler) +void +DECOMPRESS_JPEG_RECT(const Rect& r) { - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - int w = r.width(); - int h = r.height(); - int pixelsize; - rdr::U8 *dstBuf = NULL; - bool dstBufIsTemp = false; - const rfb::PixelFormat& pf = handler->cp.pf(); - // Read length int compressedLen = is->readCompactLength(); if (compressedLen <= 0) { @@ -246,97 +252,21 @@ DecompressJpegRect(const Rect& r, rdr::InStream* is, } is->readBytes(netbuf, compressedLen); - // Set up JPEG decompression - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - JpegSetSrcManager(&cinfo, (char*)netbuf, compressedLen); - jpeg_read_header(&cinfo, TRUE); + // We always use direct decoding with JPEG images + int stride; + rdr::U8 *buf = handler->getRawPixelsRW(r, &stride); + jd.decompress(netbuf, compressedLen, buf, stride * clientpf.bpp / 8, r, + clientpf); + handler->releaseRawPixels(r); - cinfo.out_color_space = JCS_RGB; - pixelsize = 3; - -#ifdef JCS_EXTENSIONS - // Try to have libjpeg output directly to our native format - if (pf.is888()) { - int redShift, greenShift, blueShift; - - if(pf.bigEndian) { - redShift = 24 - pf.redShift; - greenShift = 24 - pf.greenShift; - blueShift = 24 - pf.blueShift; - } else { - redShift = pf.redShift; - greenShift = pf.greenShift; - blueShift = pf.blueShift; - } - - // libjpeg can only handle some "standard" formats - if(redShift == 0 && greenShift == 8 && blueShift == 16) - cinfo.out_color_space = JCS_EXT_RGBX; - if(redShift == 16 && greenShift == 8 && blueShift == 0) - cinfo.out_color_space = JCS_EXT_BGRX; - if(redShift == 24 && greenShift == 16 && blueShift == 8) - cinfo.out_color_space = JCS_EXT_XBGR; - if(redShift == 8 && greenShift == 16 && blueShift == 24) - cinfo.out_color_space = JCS_EXT_XRGB; - - if (cinfo.out_color_space != JCS_RGB) { - dstBuf = (rdr::U8 *)buf; - pixelsize = 4; - } - } -#endif - - if (cinfo.out_color_space == JCS_RGB) { - dstBuf = new rdr::U8[w * h * pixelsize]; - dstBufIsTemp = true; - } - - JSAMPROW *rowPointer = new JSAMPROW[h]; - for (int dy = 0; dy < h; dy++) - rowPointer[dy] = (JSAMPROW)(&dstBuf[dy * w * pixelsize]); - - jpeg_start_decompress(&cinfo); - if (cinfo.output_width != (unsigned)r.width() || cinfo.output_height != (unsigned)r.height() || - cinfo.output_components != pixelsize) { - jpeg_destroy_decompress(&cinfo); - throw Exception("Tight Encoding: Wrong JPEG data received.\n"); - } - - // Decompress - const rfb::PixelFormat& myFormat = handler->cp.pf(); - while (cinfo.output_scanline < cinfo.output_height) { - jpeg_read_scanlines(&cinfo, &rowPointer[cinfo.output_scanline], - cinfo.output_height - cinfo.output_scanline); - if (jpegError) { - break; - } - } - - delete [] rowPointer; - - if (cinfo.out_color_space == JCS_RGB) - myFormat.bufferFromRGB((rdr::U8*)buf, dstBuf, w * h); - - IMAGE_RECT(r, buf); - - if (!jpegError) { - jpeg_finish_decompress(&cinfo); - } - - jpeg_destroy_decompress(&cinfo); - - if (dstBufIsTemp) delete [] dstBuf; delete [] netbuf; - - return !jpegError; } #if BPP == 32 -static void -FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize, - PIXEL_T* buf, CMsgHandler* handler) +void +TightDecoder::FilterGradient24(rdr::InStream* is, PIXEL_T* buf, int stride, + const Rect& r, int dataSize) { int x, y, c; static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; @@ -354,7 +284,6 @@ FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize, is->readBytes(netbuf, dataSize); // Set up shortcut variables - const rfb::PixelFormat& myFormat = handler->cp.pf(); int rectHeight = r.height(); int rectWidth = r.width(); @@ -364,21 +293,21 @@ FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize, pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c]; thisRow[c] = pix[c]; } - myFormat.bufferFromRGB((rdr::U8*)&buf[y*rectWidth], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1, NULL); /* Remaining pixels of a row */ for (x = 1; x < rectWidth; x++) { 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] = netbuf[(y*rectWidth+x)*3+c] + est[c]; - thisRow[x*3+c] = pix[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] = netbuf[(y*rectWidth+x)*3+c] + est[c]; + thisRow[x*3+c] = pix[c]; } - myFormat.bufferFromRGB((rdr::U8*)&buf[y*rectWidth+x], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1, NULL); } memcpy(prevRow, thisRow, sizeof(prevRow)); @@ -389,9 +318,9 @@ FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize, #endif -static void -FilterGradient(const Rect& r, rdr::InStream* is, int dataSize, - PIXEL_T* buf, CMsgHandler* handler) +void +FILTER_GRADIENT(rdr::InStream* is, PIXEL_T* buf, int stride, const Rect& r, + int dataSize) { int x, y, c; static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)]; @@ -409,19 +338,18 @@ FilterGradient(const Rect& r, rdr::InStream* is, int dataSize, is->readBytes(netbuf, dataSize); // Set up shortcut variables - const rfb::PixelFormat& myFormat = handler->cp.pf(); int rectHeight = r.height(); int rectWidth = r.width(); for (y = 0; y < rectHeight; y++) { /* First pixel in a row */ - myFormat.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1, NULL); + serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1, NULL); for (c = 0; c < 3; c++) pix[c] += prevRow[c]; memcpy(thisRow, pix, sizeof(pix)); - myFormat.bufferFromRGB((rdr::U8*)&buf[y*rectWidth], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1, NULL); /* Remaining pixels of a row */ for (x = 1; x < rectWidth; x++) { @@ -434,13 +362,13 @@ FilterGradient(const Rect& r, rdr::InStream* is, int dataSize, } } - myFormat.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1, NULL); + serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1, NULL); for (c = 0; c < 3; c++) pix[c] += est[c]; memcpy(&thisRow[x*3], pix, sizeof(pix)); - myFormat.bufferFromRGB((rdr::U8*)&buf[y*rectWidth+x], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1, NULL); } memcpy(prevRow, thisRow, sizeof(prevRow)); @@ -449,7 +377,39 @@ FilterGradient(const Rect& r, rdr::InStream* is, int dataSize, delete [] netbuf; } +void +DIRECT_FILL_RECT(const Rect& r, Pixel pix) { + + int stride; + PIXEL_T *buf = (PIXEL_T *)handler->getRawPixelsRW(r, &stride); + + int w = r.width(), h = r.height(); + PIXEL_T *ptr = buf; +#if BPP != 8 + int pad = stride - w; +#endif + + while (h > 0) { +#if BPP == 8 + memset(ptr, pix, w); + ptr += stride; +#else + PIXEL_T *endOfRow = ptr + w; + while (ptr < endOfRow) { + *ptr++ = pix; + } + ptr += pad; +#endif + h--; + } + + handler->releaseRawPixels(r); +} + #undef TIGHT_MIN_TO_COMPRESS +#undef DIRECT_FILL_RECT +#undef FILTER_GRADIENT +#undef DECOMPRESS_JPEG_RECT #undef TIGHT_DECODE #undef READ_PIXEL #undef PIXEL_T diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index 4e741276..3d3d582d 100644 --- a/vncviewer/CConn.cxx +++ b/vncviewer/CConn.cxx @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2009-2011 Pierre Ossman for Cendio AB + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -411,6 +412,14 @@ void CConn::setCursor(int width, int height, const Point& hotspot, desktop->setCursor(width, height, hotspot, data, mask); } +rdr::U8* CConn::getRawPixelsRW(const rfb::Rect& r, int* stride) { + return desktop->getPixelsRW(r, stride); +} +void CConn::releaseRawPixels(const rfb::Rect& r) { + desktop->damageRect(r); +} + + ////////////////////// Internal methods ////////////////////// void CConn::resizeFramebuffer() diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h index 3cde6d5f..d6177fcd 100644 --- a/vncviewer/CConn.h +++ b/vncviewer/CConn.h @@ -67,6 +67,11 @@ public: void imageRect(const rfb::Rect& r, void* p); void copyRect(const rfb::Rect& r, int sx, int sy); + rdr::U8* getRawPixelsRW(const rfb::Rect& r, int* stride); + void releaseRawPixels(const rfb::Rect& r); + + const rfb::PixelFormat &getPreferredPF() { return fullColourPF; } + void setCursor(int width, int height, const rfb::Point& hotspot, void* data, void* mask); diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index a190b700..fbb5f954 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -61,6 +61,13 @@ public: viewport->copyRect(r, srcX, srcY); } + rdr::U8* getPixelsRW(const rfb::Rect& r, int* stride) { + return viewport->getPixelsRW(r, stride); + } + void damageRect(const rfb::Rect& r) { + viewport->damageRect(r); + } + void resizeFramebuffer(int new_w, int new_h); void setCursor(int width, int height, const rfb::Point& hotspot, diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index 144ad420..c66c19a0 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -97,6 +97,16 @@ public: damageRect(r); } + rdr::U8* getPixelsRW(const rfb::Rect& r, int* stride) { + return frameBuffer->getPixelsRW(r, stride); + } + + void damageRect(const rfb::Rect& r) { + damage.assign_union(rfb::Region(r)); + if (!Fl::has_timeout(handleUpdateTimeout, this)) + Fl::add_timeout(0.500, handleUpdateTimeout, this); + }; + void setCursor(int width, int height, const rfb::Point& hotspot, void* data, void* mask); @@ -110,12 +120,6 @@ public: private: - void damageRect(const rfb::Rect& r) { - damage.assign_union(rfb::Region(r)); - if (!Fl::has_timeout(handleUpdateTimeout, this)) - Fl::add_timeout(0.500, handleUpdateTimeout, this); - }; - static void handleUpdateTimeout(void *data); void commitColourMap(); -- 2.39.5