]> source.dussan.org Git - tigervnc.git/commitdiff
Throttle overlapping screen updates
authorPierre Ossman <ossman@cendio.se>
Wed, 18 Nov 2015 15:24:16 +0000 (16:24 +0100)
committerPierre Ossman <ossman@cendio.se>
Fri, 27 Nov 2015 10:15:38 +0000 (11:15 +0100)
We need to make sure the display server has finished reading our
previous update before we overwrite the buffer with the next update.

vncviewer/CConn.cxx
vncviewer/PlatformPixelBuffer.cxx
vncviewer/PlatformPixelBuffer.h
vncviewer/X11PixelBuffer.cxx
vncviewer/X11PixelBuffer.h

index fb136b5fe09b620cfd82ac9f86509e849480d14c..262dd2ce05cd78a9a00b7c8007619e6198660460 100644 (file)
@@ -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);
 }
index 522bad3f9755580d64c2d6062d4b343d5f2f2360..876ab94a1e9b5781d36470e63fb79888b007110a 100644 (file)
@@ -44,3 +44,8 @@ rfb::Rect PlatformPixelBuffer::getDamage(void)
 
   return r;
 }
+
+bool PlatformPixelBuffer::isRendering(void)
+{
+  return false;
+}
index 795273a9bea4fc025f19144f559d06a990c56050..9f0e3b1662595ac665842b7458ed05bee455570b 100644 (file)
@@ -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;
index 9196fdca38d37991144287fa4f80d8c68f8d44a9..046676eb175df9cc6bf55bc14fcabf633060d974 100644 (file)
 #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;
+}
index c2ffdc283fec11dddb633bd48fbb1e9de8096527..115984da591ee93053feed5cfccd0bfe25200ee0 100644 (file)
@@ -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;
 };