Make the comparing update tracker a bit more flexible. It can now be in an
"auto" state where it will be enabled until we deem that the client is better
of without it (currently triggered by explicitly stating a low compression
level).
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4809 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx
index 42a9e19..43287e0 100644
--- a/common/rfb/ComparingUpdateTracker.cxx
+++ b/common/rfb/ComparingUpdateTracker.cxx
@@ -25,7 +25,7 @@
using namespace rfb;
ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
- : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true)
+ : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true), enabled(true)
{
changed.assign_union(fb->getRect());
}
@@ -37,35 +37,60 @@
#define BLOCK_SIZE 16
-void ComparingUpdateTracker::compare()
+bool ComparingUpdateTracker::compare()
{
std::vector<Rect> rects;
std::vector<Rect>::iterator i;
+ if (!enabled)
+ return false;
+
if (firstCompare) {
// NB: We leave the change region untouched on this iteration,
// since in effect the entire framebuffer has changed.
oldFb.setSize(fb->width(), fb->height());
+
for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
int srcStride;
const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
oldFb.imageRect(pos, srcData, srcStride);
}
+
firstCompare = false;
- } else {
- copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
- for (i = rects.begin(); i != rects.end(); i++)
- oldFb.copyRect(*i, copy_delta);
- changed.get_rects(&rects);
-
- Region newChanged;
- for (i = rects.begin(); i != rects.end(); i++)
- compareRect(*i, &newChanged);
-
- changed = newChanged;
+ return false;
}
+
+ copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
+ for (i = rects.begin(); i != rects.end(); i++)
+ oldFb.copyRect(*i, copy_delta);
+
+ changed.get_rects(&rects);
+
+ Region newChanged;
+ for (i = rects.begin(); i != rects.end(); i++)
+ compareRect(*i, &newChanged);
+
+ if (changed.equals(newChanged))
+ return false;
+
+ changed = newChanged;
+
+ return true;
+}
+
+void ComparingUpdateTracker::enable()
+{
+ enabled = true;
+}
+
+void ComparingUpdateTracker::disable()
+{
+ enabled = false;
+
+ // Make sure we update the framebuffer next time we get enabled
+ firstCompare = true;
}
void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
diff --git a/common/rfb/ComparingUpdateTracker.h b/common/rfb/ComparingUpdateTracker.h
index 5d2e5ed..fccc222 100644
--- a/common/rfb/ComparingUpdateTracker.h
+++ b/common/rfb/ComparingUpdateTracker.h
@@ -29,14 +29,23 @@
~ComparingUpdateTracker();
// compare() does the comparison and reduces its changed and copied regions
- // as appropriate.
+ // as appropriate. Returns true if the regions were altered.
- virtual void compare();
+ virtual bool compare();
+
+ // enable()/disable() turns the comparing functionality on/off. With it
+ // disabled, the object will behave like a dumb update tracker (i.e.
+ // compare() will be a no-op). It is harmless to repeatedly call these
+ // methods.
+
+ virtual void enable();
+ virtual void disable();
private:
void compareRect(const Rect& r, Region* newchanged);
PixelBuffer* fb;
ManagedPixelBuffer oldFb;
bool firstCompare;
+ bool enabled;
};
}
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
index 27e116e..ae2fd24 100644
--- a/common/rfb/ServerCore.cxx
+++ b/common/rfb/ServerCore.cxx
@@ -47,10 +47,11 @@
"The number of milliseconds to wait for a client which is no longer "
"responding",
20000, 0);
-rfb::BoolParameter rfb::Server::compareFB
+rfb::IntParameter rfb::Server::compareFB
("CompareFB",
- "Perform pixel comparison on framebuffer to reduce unnecessary updates",
- false);
+ "Perform pixel comparison on framebuffer to reduce unnecessary updates "
+ "(0: never, 1: always, 2: auto)",
+ 2);
rfb::BoolParameter rfb::Server::protocol3_3
("Protocol3.3",
"Always use protocol version 3.3 for backwards compatibility with "
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
index 68d7b74..e12a8bc 100644
--- a/common/rfb/ServerCore.h
+++ b/common/rfb/ServerCore.h
@@ -37,7 +37,7 @@
static IntParameter maxConnectionTime;
static IntParameter maxIdleTime;
static IntParameter clientWaitTimeMillis;
- static BoolParameter compareFB;
+ static IntParameter compareFB;
static BoolParameter protocol3_3;
static BoolParameter alwaysShared;
static BoolParameter neverShared;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index d0cdf86..466d6d5 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -326,6 +326,16 @@
return secsToMillis(timeLeft);
}
+
+bool VNCSConnectionST::getComparerState()
+{
+ // We interpret a low compression level as an indication that the client
+ // wants to prioritise CPU usage over bandwidth, and hence disable the
+ // comparing update tracker.
+ return (cp.compressLevel == -1) || (cp.compressLevel > 1);
+}
+
+
// renderedCursorChange() is called whenever the server-side rendered cursor
// changes shape or position. It ensures that the next update will clean up
// the old rendered cursor and if necessary draw the new rendered cursor.
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 8742fa6..72dc59c 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -85,6 +85,10 @@
// The following methods never throw exceptions nor do they ever delete the
// SConnectionST object.
+ // getComparerState() returns if this client would like the framebuffer
+ // comparer to be enabled.
+ bool getComparerState();
+
// renderedCursorChange() is called whenever the server-side rendered
// cursor changes shape or position. It ensures that the next update will
// clean up the old rendered cursor and if necessary draw the new rendered
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 5c13596..1e3f61a 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -596,10 +596,13 @@
pb->grabRegion(toCheck);
- if (rfb::Server::compareFB) {
- comparer->compare();
+ if (getComparerState())
+ comparer->enable();
+ else
+ comparer->disable();
+
+ if (comparer->compare())
comparer->getUpdateInfo(&ui, pb->getRect());
- }
if (renderCursor) {
pb->getImage(renderedCursor.data,
@@ -665,3 +668,19 @@
(*ci)->screenLayoutChangeOrClose(reasonOtherClient);
}
}
+
+bool VNCServerST::getComparerState()
+{
+ if (rfb::Server::compareFB == 0)
+ return false;
+ if (rfb::Server::compareFB != 2)
+ return true;
+
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
+ ci_next = ci; ci_next++;
+ if ((*ci)->getComparerState())
+ return true;
+ }
+ return false;
+}
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 47a4801..2fed0a8 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -238,6 +238,8 @@
void notifyScreenLayoutChange(VNCSConnectionST *requester);
+ bool getComparerState();
+
QueryConnectionHandler* queryConnectionHandler;
KeyRemapper* keyRemapper;
bool useEconomicTranslate;