Skip to content

Commit b1df8ba

Browse files
committed
VNCConn: avoid holding mutex_framebuffer for too long
...by introducing a 2nd front buffer the UI can read from while libvncclient is busy writing to the client's back buffer. Fixes unresponsive UI due to the VNC thread unfairly grabbing the mutex in certain edge cases like when sending no input at all. re #152 #282
1 parent a43ad40 commit b1df8ba

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

src/VNCConn.cpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ VNCConn::VNCConn(void* p) : condition_auth(mutex_auth)
8484
parent = p;
8585

8686
cl = 0;
87+
framebuffer_front = 0;
8788
multicastStatus = 0;
8889
latency = -1;
8990

@@ -222,10 +223,17 @@ rfbBool VNCConn::thread_alloc_framebuffer(rfbClient* client)
222223
// alloc, zeroed
223224
client->frameBuffer = (uint8_t*)calloc(1, client->width*client->height*client->format.bitsPerPixel/8);
224225

226+
// free front framebuffer
227+
if(conn->framebuffer_front)
228+
free(conn->framebuffer_front);
229+
230+
// alloc, zeroed
231+
conn->framebuffer_front = (uint8_t*)calloc(1, client->width*client->height*client->format.bitsPerPixel/8);
232+
225233
// notify our parent
226234
conn->thread_post_fbresize_notify();
227235

228-
return client->frameBuffer ? TRUE : FALSE;
236+
return (client->frameBuffer && conn->framebuffer_front) ? TRUE : FALSE;
229237
}
230238

231239

@@ -471,8 +479,6 @@ wxThread::ExitCode VNCConn::Entry()
471479

472480

473481
// request update and handle response
474-
{
475-
wxCriticalSectionLocker lock(mutex_framebuffer);
476482
if(!rfbProcessServerMessage(cl, 500))
477483
{
478484
if(errno == EINTR)
@@ -488,7 +494,7 @@ wxThread::ExitCode VNCConn::Entry()
488494
}
489495
return 0;
490496
}
491-
}
497+
492498

493499
/*
494500
Compute nacked/loss ratio: We take a ratio sample every second and put it into a sample queue
@@ -983,6 +989,20 @@ void VNCConn::thread_update_finished(rfbClient* client)
983989
VNCConn* conn = (VNCConn*) rfbClientGetClientData(client, VNCCONN_OBJ_ID);
984990
if(! conn->GetThread()->TestDestroy())
985991
{
992+
{
993+
wxCriticalSectionLocker lock(conn->mutex_framebuffer);
994+
if(client->frameBuffer && conn->framebuffer_front) {
995+
// Copy framebuffer to front buffer for UI display
996+
#ifndef NDEBUG
997+
wxStopWatch copy_timer;
998+
#endif
999+
memcpy(conn->framebuffer_front, client->frameBuffer, client->width * client->height * client->format.bitsPerPixel / 8);
1000+
#ifndef NDEBUG
1001+
wxLogDebug(wxT("VNCConn %p: copying %dx%d framebuffer took %ldms"), conn, client->width, client->height, copy_timer.Time());
1002+
#endif
1003+
}
1004+
}
1005+
9861006
if(!conn->updated_rect.IsEmpty())
9871007
conn->thread_post_update_notify(conn->updated_rect.x, conn->updated_rect.y, conn->updated_rect.width, conn->updated_rect.height);
9881008

@@ -1430,6 +1450,12 @@ void VNCConn::Shutdown()
14301450
rfbClientCleanup(cl);
14311451
cl = 0;
14321452
}
1453+
1454+
// Clean up front framebuffer
1455+
if(framebuffer_front) {
1456+
free(framebuffer_front);
1457+
framebuffer_front = 0;
1458+
}
14331459
}
14341460

14351461

@@ -1765,19 +1791,19 @@ wxBitmap VNCConn::getFrameBufferRegion(const wxRect& rect)
17651791
if(rect.x < 0 || rect.x + rect.width > getFrameBufferWidth()
17661792
|| rect.y < 0 || rect.y + rect.height > getFrameBufferHeight()
17671793
|| !cl
1768-
|| !cl->frameBuffer)
1794+
|| !framebuffer_front)
17691795
return wxBitmap();
17701796

17711797
/*
1772-
copy directly from framebuffer into a new bitmap
1798+
copy directly from front framebuffer into a new bitmap
17731799
*/
17741800

17751801
wxBitmap region(rect.width, rect.height, cl->format.bitsPerPixel);
17761802
wxAlphaPixelData region_data(region);
17771803
wxAlphaPixelData::Iterator region_it(region_data);
17781804

17791805
int bytesPerPixel = cl->format.bitsPerPixel/8;
1780-
uint8_t *fbsub_it = cl->frameBuffer + rect.y*cl->width*bytesPerPixel + rect.x*bytesPerPixel;
1806+
uint8_t *fbsub_it = framebuffer_front + rect.y*cl->width*bytesPerPixel + rect.x*bytesPerPixel;
17811807

17821808
for( int y = 0; y < rect.height; ++y )
17831809
{

src/VNCConn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class VNCConn: public wxEvtHandler, public wxThreadHelper
234234

235235
wxRect updated_rect;
236236

237+
uint8_t* framebuffer_front; // framebuffer for UI reading
237238
wxCriticalSection mutex_framebuffer;
238239

239240
int multicastStatus;

0 commit comments

Comments
 (0)