We need to make sure the display server has finished reading our previous update before we overwrite the buffer with the next update.tags/v1.6.90
#include "CConn.h" | #include "CConn.h" | ||||
#include "OptionsDialog.h" | #include "OptionsDialog.h" | ||||
#include "DesktopWindow.h" | #include "DesktopWindow.h" | ||||
#include "PlatformPixelBuffer.h" | |||||
#include "i18n.h" | #include "i18n.h" | ||||
#include "parameters.h" | #include "parameters.h" | ||||
#include "vncviewer.h" | #include "vncviewer.h" | ||||
// one. | // one. | ||||
void CConn::framebufferUpdateStart() | void CConn::framebufferUpdateStart() | ||||
{ | { | ||||
ModifiablePixelBuffer* pb; | |||||
PlatformPixelBuffer* ppb; | |||||
CConnection::framebufferUpdateStart(); | CConnection::framebufferUpdateStart(); | ||||
// Note: This might not be true if sync fences are supported | // Note: This might not be true if sync fences are supported | ||||
requestNewUpdate(); | 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 | // Update the screen prematurely for very slow updates | ||||
Fl::add_timeout(1.0, handleUpdateTimeout, this); | Fl::add_timeout(1.0, handleUpdateTimeout, this); | ||||
} | } |
return r; | return r; | ||||
} | } | ||||
bool PlatformPixelBuffer::isRendering(void) | |||||
{ | |||||
return false; | |||||
} |
virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0; | virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0; | ||||
rfb::Rect getDamage(void); | rfb::Rect getDamage(void); | ||||
virtual bool isRendering(void); | |||||
protected: | protected: | ||||
os::Mutex mutex; | os::Mutex mutex; | ||||
rfb::Region damage; | rfb::Region damage; |
#include <config.h> | #include <config.h> | ||||
#endif | #endif | ||||
#include <assert.h> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <FL/Fl.H> | |||||
#include <FL/x.H> | #include <FL/x.H> | ||||
#include <rfb/LogWriter.h> | #include <rfb/LogWriter.h> | ||||
static rfb::LogWriter vlog("X11PixelBuffer"); | static rfb::LogWriter vlog("X11PixelBuffer"); | ||||
std::list<X11PixelBuffer*> X11PixelBuffer::shmList; | |||||
static PixelFormat display_pf() | static PixelFormat display_pf() | ||||
{ | { | ||||
int i; | int i; | ||||
X11PixelBuffer::X11PixelBuffer(int width, int height) : | X11PixelBuffer::X11PixelBuffer(int width, int height) : | ||||
PlatformPixelBuffer(display_pf(), width, height, NULL, 0), | PlatformPixelBuffer(display_pf(), width, height, NULL, 0), | ||||
shminfo(NULL), xim(NULL) | |||||
shminfo(NULL), xim(NULL), pendingPutImage(0) | |||||
{ | { | ||||
// Might not be open at this point | // Might not be open at this point | ||||
fl_open_display(); | fl_open_display(); | ||||
{ | { | ||||
if (shminfo) { | if (shminfo) { | ||||
vlog.debug("Freeing shared memory XImage"); | vlog.debug("Freeing shared memory XImage"); | ||||
shmList.remove(this); | |||||
Fl::remove_system_handler(handleSystemEvent); | |||||
shmdt(shminfo->shmaddr); | shmdt(shminfo->shmaddr); | ||||
shmctl(shminfo->shmid, IPC_RMID, 0); | shmctl(shminfo->shmid, IPC_RMID, 0); | ||||
delete shminfo; | delete shminfo; | ||||
void X11PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) | 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); | 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; | static bool caughtError; | ||||
if (caughtError) | if (caughtError) | ||||
goto free_shmaddr; | 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"); | vlog.debug("Using shared memory XImage"); | ||||
return 1; | return 1; | ||||
return 0; | 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; | |||||
} |
#include <sys/shm.h> | #include <sys/shm.h> | ||||
#include <X11/extensions/XShm.h> | #include <X11/extensions/XShm.h> | ||||
#include <list> | |||||
#include "PlatformPixelBuffer.h" | #include "PlatformPixelBuffer.h" | ||||
class X11PixelBuffer: public PlatformPixelBuffer { | class X11PixelBuffer: public PlatformPixelBuffer { | ||||
virtual void draw(int src_x, int src_y, int x, int y, int w, int h); | virtual void draw(int src_x, int src_y, int x, int y, int w, int h); | ||||
virtual bool isRendering(void); | |||||
protected: | protected: | ||||
int setupShm(); | int setupShm(); | ||||
static int handleSystemEvent(void* event, void* data); | |||||
protected: | protected: | ||||
XShmSegmentInfo *shminfo; | XShmSegmentInfo *shminfo; | ||||
XImage *xim; | XImage *xim; | ||||
int pendingPutImage; | |||||
static std::list<X11PixelBuffer*> shmList; | |||||
}; | }; | ||||