From 8efc7b47cc744b3ee4b7ae20f88c9e3aa775eefe Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 23 Mar 2018 11:45:51 +0100 Subject: [PATCH] Send lossless refresh even with pending updates There might be parts of the screen that haven't changed and can therefore be refreshed. Figure which parts these are and send just those. --- common/rfb/VNCSConnectionST.cxx | 31 +++++++++++++++++++------------ common/rfb/VNCServerST.cxx | 14 +++++++++----- common/rfb/VNCServerST.h | 2 +- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 3f92a429..126fb4e8 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -965,18 +965,13 @@ void VNCSConnectionST::writeNoDataUpdate() void VNCSConnectionST::writeDataUpdate() { - Region req; + Region req, pending; UpdateInfo ui; bool needNewUpdateInfo; const RenderedCursor *cursor; updates.enable_copyrect(cp.useCopyRect); - // See if we are allowed to send anything right now (the framebuffer - // might have changed in ways we haven't yet been informed of). - if (!server->checkUpdate()) - return; - // See what the client has requested (if anything) if (continuousUpdates) req = cuRegion.union_(requested); @@ -986,6 +981,9 @@ void VNCSConnectionST::writeDataUpdate() if (req.is_empty()) return; + // Get any framebuffer changes we haven't yet been informed of + pending = server->getPendingRegion(); + // Get the lists of updates. Prior to exporting the data to the `ui' object, // getUpdateInfo() will normalize the `updates' object such way that its // `changed' and `copied' regions would not intersect. @@ -1027,17 +1025,24 @@ void VNCSConnectionST::writeDataUpdate() updateRenderedCursor = false; } - // Return if there is nothing to send the client. - - if (updates.is_empty() && !writer()->needFakeUpdate() && - !encodeManager.needsLosslessRefresh(req)) - return; - // The `updates' object could change, make sure we have valid update info. if (needNewUpdateInfo) updates.getUpdateInfo(&ui, req); + // If there are queued updates then we cannot safely send an update + // without risking a partially updated screen + + if (!pending.is_empty()) { + // However we might still be able to send a lossless refresh + req.assign_subtract(pending); + req.assign_subtract(ui.changed); + req.assign_subtract(ui.copied); + + ui.changed.clear(); + ui.copied.clear(); + } + // Does the client need a server-side rendered cursor? cursor = NULL; @@ -1059,6 +1064,8 @@ void VNCSConnectionST::writeDataUpdate() damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect)); } + // Return if there is nothing to send the client. + if (ui.is_empty() && !writer()->needFakeUpdate() && !encodeManager.needsLosslessRefresh(req)) return; diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 15df71b9..95870c92 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -656,17 +656,21 @@ void VNCServerST::writeUpdate() // checkUpdate() is called by clients to see if it is safe to read from // the framebuffer at this time. -bool VNCServerST::checkUpdate() +Region VNCServerST::getPendingRegion() { + UpdateInfo ui; + // Block clients as the frame buffer cannot be safely accessed if (blockCounter > 0) - return false; + return pb->getRect(); // Block client from updating if there are pending updates - if (!comparer->is_empty()) - return false; + if (comparer->is_empty()) + return Region(); + + comparer->getUpdateInfo(&ui, pb->getRect()); - return true; + return ui.changed.union_(ui.copied); } const RenderedCursor* VNCServerST::getRenderedCursor() diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 9a1a44d1..b7845ddd 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -229,7 +229,7 @@ namespace rfb { void stopFrameClock(); int msToNextUpdate(); void writeUpdate(); - bool checkUpdate(); + Region getPendingRegion(); const RenderedCursor* getRenderedCursor(); void notifyScreenLayoutChange(VNCSConnectionST *requester); -- 2.39.5