From: Pierre Ossman Date: Thu, 20 Sep 2018 08:52:15 +0000 (+0200) Subject: Allow perceptually lossless refresh X-Git-Tag: v1.9.90~81^2~5^2~1 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=beab2b6e4adcdab1fd71964c5ab7533c6050edbf;p=tigervnc.git Allow perceptually lossless refresh Loosen the definition of "lossless" a bit so that we can use high quality JPEG to refresh damaged parts of the screen. Although this isn't bit perfect, it is close enough that most users will not be able to tell the difference. Level 9 is used rather than level 8 because some monitors have exaggerated contrast that allows the artefacts from level 8 to be noticeable. --- diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index d783d54b..02128f7f 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -364,6 +364,8 @@ void EncodeManager::prepareEncoders(bool allowLossy) enum EncoderClass solid, bitmap, bitmapRLE; enum EncoderClass indexed, indexedRLE, fullColour; + bool allowJPEG; + rdr::S32 preferred; std::vector::iterator iter; @@ -371,6 +373,12 @@ void EncodeManager::prepareEncoders(bool allowLossy) solid = bitmap = bitmapRLE = encoderRaw; indexed = indexedRLE = fullColour = encoderRaw; + allowJPEG = conn->cp.pf().bpp >= 16; + if (!allowLossy) { + if (encoders[encoderTightJPEG]->losslessQuality == -1) + allowJPEG = false; + } + // Try to respect the client's wishes preferred = conn->getPreferredEncoding(); switch (preferred) { @@ -383,8 +391,7 @@ void EncodeManager::prepareEncoders(bool allowLossy) bitmapRLE = indexedRLE = fullColour = encoderHextile; break; case encodingTight: - if (encoders[encoderTightJPEG]->isSupported() && - (conn->cp.pf().bpp >= 16) && allowLossy) + if (encoders[encoderTightJPEG]->isSupported() && allowJPEG) fullColour = encoderTightJPEG; else fullColour = encoderTight; @@ -401,8 +408,7 @@ void EncodeManager::prepareEncoders(bool allowLossy) // Any encoders still unassigned? if (fullColour == encoderRaw) { - if (encoders[encoderTightJPEG]->isSupported() && - (conn->cp.pf().bpp >= 16) && allowLossy) + if (encoders[encoderTightJPEG]->isSupported() && allowJPEG) fullColour = encoderTightJPEG; else if (encoders[encoderZRLE]->isSupported()) fullColour = encoderZRLE; @@ -460,9 +466,17 @@ void EncodeManager::prepareEncoders(bool allowLossy) encoder = encoders[*iter]; encoder->setCompressLevel(conn->cp.compressLevel); - encoder->setQualityLevel(conn->cp.qualityLevel); - encoder->setFineQualityLevel(conn->cp.fineQualityLevel, - conn->cp.subsampling); + + if (allowLossy) { + encoder->setQualityLevel(conn->cp.qualityLevel); + encoder->setFineQualityLevel(conn->cp.fineQualityLevel, + conn->cp.subsampling); + } else { + int level = __rfbmax(conn->cp.qualityLevel, + encoder->losslessQuality); + encoder->setQualityLevel(level); + encoder->setFineQualityLevel(-1, subsampleUndefined); + } } } @@ -567,7 +581,9 @@ Encoder *EncodeManager::startRect(const Rect& rect, int type) encoder = encoders[klass]; conn->writer()->startRect(rect, encoder->encoding); - if (encoder->flags & EncoderLossy) + if ((encoder->flags & EncoderLossy) && + ((encoder->losslessQuality == -1) || + (encoder->getQualityLevel() < encoder->losslessQuality))) lossyRegion.assign_union(Region(rect)); else lossyRegion.assign_subtract(Region(rect)); diff --git a/common/rfb/Encoder.cxx b/common/rfb/Encoder.cxx index 18b66809..0e29f1df 100644 --- a/common/rfb/Encoder.cxx +++ b/common/rfb/Encoder.cxx @@ -24,9 +24,11 @@ using namespace rfb; Encoder::Encoder(SConnection *conn_, int encoding_, - enum EncoderFlags flags_, unsigned int maxPaletteSize_) : + enum EncoderFlags flags_, + unsigned int maxPaletteSize_, int losslessQuality_) : encoding(encoding_), flags(flags_), - maxPaletteSize(maxPaletteSize_), conn(conn_) + maxPaletteSize(maxPaletteSize_), losslessQuality(losslessQuality_), + conn(conn_) { } diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h index e135ec0e..d5a0288e 100644 --- a/common/rfb/Encoder.h +++ b/common/rfb/Encoder.h @@ -42,7 +42,8 @@ namespace rfb { class Encoder { public: Encoder(SConnection* conn, int encoding, - enum EncoderFlags flags, unsigned int maxPaletteSize=-1); + enum EncoderFlags flags, unsigned int maxPaletteSize=-1, + int losslessQuality=-1); virtual ~Encoder(); // isSupported() should return a boolean indicating if this encoder @@ -95,6 +96,10 @@ namespace rfb { // Maximum size of the palette per rect const unsigned int maxPaletteSize; + // Minimum level where the quality loss will not be noticed by + // most users (only relevant with EncoderLossy flag) + const int losslessQuality; + protected: SConnection* conn; }; diff --git a/common/rfb/TightJPEGEncoder.cxx b/common/rfb/TightJPEGEncoder.cxx index bbe4f8fa..38cb4eb7 100644 --- a/common/rfb/TightJPEGEncoder.cxx +++ b/common/rfb/TightJPEGEncoder.cxx @@ -64,7 +64,8 @@ static const struct TightJPEGConfiguration conf[10] = { TightJPEGEncoder::TightJPEGEncoder(SConnection* conn) : - Encoder(conn, encodingTight, (EncoderFlags)(EncoderUseNativePF | EncoderLossy)), + Encoder(conn, encodingTight, + (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1, 9), qualityLevel(-1), fineQuality(-1), fineSubsampling(subsampleUndefined) { }