summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2015-11-18 16:24:16 +0100
committerPierre Ossman <ossman@cendio.se>2015-11-27 11:15:38 +0100
commitc9dd3a40234b54c7cc9bade71a6cd84af5325fb2 (patch)
tree994af4dfd3fd75626007c15b316eb8148b443caf
parent5102fa96876907adca3d0897d67108c60a2545b0 (diff)
downloadtigervnc-c9dd3a40234b54c7cc9bade71a6cd84af5325fb2.tar.gz
tigervnc-c9dd3a40234b54c7cc9bade71a6cd84af5325fb2.zip
Throttle overlapping screen updates
We need to make sure the display server has finished reading our previous update before we overwrite the buffer with the next update.
-rw-r--r--vncviewer/CConn.cxx20
-rw-r--r--vncviewer/PlatformPixelBuffer.cxx5
-rw-r--r--vncviewer/PlatformPixelBuffer.h2
-rw-r--r--vncviewer/X11PixelBuffer.cxx53
-rw-r--r--vncviewer/X11PixelBuffer.h9
5 files changed, 85 insertions, 4 deletions
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index fb136b5f..262dd2ce 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -46,6 +46,7 @@
#include "CConn.h"
#include "OptionsDialog.h"
#include "DesktopWindow.h"
+#include "PlatformPixelBuffer.h"
#include "i18n.h"
#include "parameters.h"
#include "vncviewer.h"
@@ -336,6 +337,9 @@ void CConn::setName(const char* name)
// one.
void CConn::framebufferUpdateStart()
{
+ ModifiablePixelBuffer* pb;
+ PlatformPixelBuffer* ppb;
+
CConnection::framebufferUpdateStart();
// Note: This might not be true if sync fences are supported
@@ -343,6 +347,22 @@ void CConn::framebufferUpdateStart()
requestNewUpdate();
+ // We might still be rendering the previous update
+ pb = getFramebuffer();
+ assert(pb != NULL);
+ ppb = dynamic_cast<PlatformPixelBuffer*>(pb);
+ assert(ppb != NULL);
+ if (ppb->isRendering()) {
+ // Need to stop monitoring the socket or we'll just busy loop
+ assert(sock != NULL);
+ Fl::remove_fd(sock->getFd());
+
+ while (ppb->isRendering())
+ run_mainloop();
+
+ Fl::add_fd(sock->getFd(), FL_READ | FL_EXCEPT, socketEvent, this);
+ }
+
// Update the screen prematurely for very slow updates
Fl::add_timeout(1.0, handleUpdateTimeout, this);
}
diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
index 522bad3f..876ab94a 100644
--- a/vncviewer/PlatformPixelBuffer.cxx
+++ b/vncviewer/PlatformPixelBuffer.cxx
@@ -44,3 +44,8 @@ rfb::Rect PlatformPixelBuffer::getDamage(void)
return r;
}
+
+bool PlatformPixelBuffer::isRendering(void)
+{
+ return false;
+}
diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h
index 795273a9..9f0e3b16 100644
--- a/vncviewer/PlatformPixelBuffer.h
+++ b/vncviewer/PlatformPixelBuffer.h
@@ -34,6 +34,8 @@ public:
virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0;
rfb::Rect getDamage(void);
+ virtual bool isRendering(void);
+
protected:
os::Mutex mutex;
rfb::Region damage;
diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx
index 9196fdca..046676eb 100644
--- a/vncviewer/X11PixelBuffer.cxx
+++ b/vncviewer/X11PixelBuffer.cxx
@@ -21,8 +21,10 @@
#include <config.h>
#endif
+#include <assert.h>
#include <stdlib.h>
+#include <FL/Fl.H>
#include <FL/x.H>
#include <rfb/LogWriter.h>
@@ -35,6 +37,8 @@ using namespace rfb;
static rfb::LogWriter vlog("X11PixelBuffer");
+std::list<X11PixelBuffer*> X11PixelBuffer::shmList;
+
static PixelFormat display_pf()
{
int i;
@@ -97,7 +101,7 @@ static PixelFormat display_pf()
X11PixelBuffer::X11PixelBuffer(int width, int height) :
PlatformPixelBuffer(display_pf(), width, height, NULL, 0),
- shminfo(NULL), xim(NULL)
+ shminfo(NULL), xim(NULL), pendingPutImage(0)
{
// Might not be open at this point
fl_open_display();
@@ -122,6 +126,8 @@ X11PixelBuffer::~X11PixelBuffer()
{
if (shminfo) {
vlog.debug("Freeing shared memory XImage");
+ shmList.remove(this);
+ Fl::remove_system_handler(handleSystemEvent);
shmdt(shminfo->shmaddr);
shmctl(shminfo->shmid, IPC_RMID, 0);
delete shminfo;
@@ -137,12 +143,18 @@ X11PixelBuffer::~X11PixelBuffer()
void X11PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h)
{
- if (shminfo)
- XShmPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h, False);
- else
+ if (shminfo) {
+ XShmPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h, True);
+ pendingPutImage++;
+ } else {
XPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h);
+ }
}
+bool X11PixelBuffer::isRendering(void)
+{
+ return pendingPutImage > 0;
+}
static bool caughtError;
@@ -202,6 +214,11 @@ int X11PixelBuffer::setupShm()
if (caughtError)
goto free_shmaddr;
+ // FLTK is a bit stupid and unreliable if you register the same
+ // callback with different data values.
+ Fl::add_system_handler(handleSystemEvent, NULL);
+ shmList.push_back(this);
+
vlog.debug("Using shared memory XImage");
return 1;
@@ -222,3 +239,31 @@ free_shminfo:
return 0;
}
+
+int X11PixelBuffer::handleSystemEvent(void* event, void* data)
+{
+ XEvent* xevent;
+ XShmCompletionEvent* shmevent;
+
+ std::list<X11PixelBuffer*>::iterator iter;
+
+ xevent = (XEvent*)event;
+ assert(xevent);
+
+ if (xevent->type != XShmGetEventBase(fl_display))
+ return 0;
+
+ shmevent = (XShmCompletionEvent*)event;
+
+ for (iter = shmList.begin();iter != shmList.end();++iter) {
+ if (shmevent->shmseg != (*iter)->shminfo->shmseg)
+ continue;
+
+ (*iter)->pendingPutImage--;
+ assert((*iter)->pendingPutImage >= 0);
+
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/vncviewer/X11PixelBuffer.h b/vncviewer/X11PixelBuffer.h
index c2ffdc28..115984da 100644
--- a/vncviewer/X11PixelBuffer.h
+++ b/vncviewer/X11PixelBuffer.h
@@ -24,6 +24,8 @@
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
+#include <list>
+
#include "PlatformPixelBuffer.h"
class X11PixelBuffer: public PlatformPixelBuffer {
@@ -33,12 +35,19 @@ public:
virtual void draw(int src_x, int src_y, int x, int y, int w, int h);
+ virtual bool isRendering(void);
+
protected:
int setupShm();
+ static int handleSystemEvent(void* event, void* data);
+
protected:
XShmSegmentInfo *shminfo;
XImage *xim;
+ int pendingPutImage;
+
+ static std::list<X11PixelBuffer*> shmList;
};