]> source.dussan.org Git - tigervnc.git/commitdiff
Allow perceptually lossless refresh
authorPierre Ossman <ossman@cendio.se>
Thu, 20 Sep 2018 08:52:15 +0000 (10:52 +0200)
committerPierre Ossman <ossman@cendio.se>
Fri, 21 Sep 2018 08:38:41 +0000 (10:38 +0200)
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.

common/rfb/EncodeManager.cxx
common/rfb/Encoder.cxx
common/rfb/Encoder.h
common/rfb/TightJPEGEncoder.cxx

index d783d54b8332510f15bab9b0d44bceee6895105b..02128f7f4ac9124bddac58b537ea4c94242cc158 100644 (file)
@@ -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<int>::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));
index 18b66809b029ab3d296afa931fb84c6a4e34812a..0e29f1dfcd5dc03ec7fafc3a5a772c02f0073fbf 100644 (file)
 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_)
 {
 }
 
index e135ec0e10dc3aec7fe45b203daf71b76144196b..d5a0288ee9ba6eebb17f4e773f8c01cef53f0445 100644 (file)
@@ -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;
   };
index bbe4f8fa4de44cbb84a9f68c48e7d475af3f2213..38cb4eb72dd3128cce7aec47fb8394f870791ef3 100644 (file)
@@ -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)
 {
 }