From 98270130c8a9052a541f9b2f96857f6972cc46ff Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 28 Feb 2024 14:20:54 +0100 Subject: [PATCH] Keep frame clock running if waiting for frame tick If there is something interested in synchronizing to a frame tick, then keep the frame clock running, even if there are no updates. This is need mainly when something starts rendering, but also when something renders much slower than the frame clock (so it is essentially constantly "starting"). Such an application will not draw anything until it gets a new frame tick, which it won't get as the frame clock is waiting for something to start drawing. --- common/rfb/VNCServer.h | 1 + common/rfb/VNCServerST.cxx | 20 ++++++++++++++++---- common/rfb/VNCServerST.h | 3 ++- unix/xserver/hw/vnc/XserverDesktop.cc | 1 + 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h index 314367eb60..b49dbfe34a 100644 --- a/common/rfb/VNCServer.h +++ b/common/rfb/VNCServer.h @@ -43,6 +43,7 @@ namespace rfb { virtual void unblockUpdates() = 0; virtual uint64_t getMsc() = 0; + virtual void queueMsc(uint64_t target) = 0; // setPixelBuffer() tells the server to use the given pixel buffer (and // optionally a modified screen layout). If this differs in size from diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index c2d406d0a7..582956de29 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -88,7 +88,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) renderedCursorInvalid(false), keyRemapper(&KeyRemapper::defInstance), idleTimer(this), disconnectTimer(this), connectTimer(this), - msc(0), frameTimer(this) + msc(0), queuedMsc(0), frameTimer(this) { slog.debug("creating single-threaded server %s", name.c_str()); @@ -262,6 +262,14 @@ uint64_t VNCServerST::getMsc() return msc; } +void VNCServerST::queueMsc(uint64_t target) +{ + if (target > queuedMsc) + queuedMsc = target; + + startFrameClock(); +} + void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout) { if (comparer) @@ -634,13 +642,17 @@ void VNCServerST::handleTimeout(Timer* t) { if (t == &frameTimer) { // We keep running until we go a full interval without any updates - if (comparer->is_empty()) - return; + if (comparer->is_empty()) { + // Unless something waits for us to advance the frame count + if (queuedMsc < msc) + return; + } // If this is the first iteration then we need to adjust the timeout frameTimer.repeat(1000/rfb::Server::frameRate); - writeUpdate(); + if (!comparer->is_empty()) + writeUpdate(); msc++; desktop->frameTick(msc); diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 719b3f366a..3436d333f0 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -82,6 +82,7 @@ namespace rfb { virtual void blockUpdates(); virtual void unblockUpdates(); virtual uint64_t getMsc(); + virtual void queueMsc(uint64_t target); virtual void setPixelBuffer(PixelBuffer* pb, const ScreenSet& layout); virtual void setPixelBuffer(PixelBuffer* pb); virtual void setScreenLayout(const ScreenSet& layout); @@ -207,7 +208,7 @@ namespace rfb { Timer disconnectTimer; Timer connectTimer; - uint64_t msc; + uint64_t msc, queuedMsc; Timer frameTimer; }; diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index 84ff98f78e..a7ec230fbf 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -154,6 +154,7 @@ uint64_t XserverDesktop::getMsc() void XserverDesktop::queueMsc(uint64_t id, uint64_t msc) { pendingMsc[id] = msc; + server->queueMsc(msc); } void XserverDesktop::abortMsc(uint64_t id)