mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 13:37:22 +00:00
[client] allow frame updates to be triggered by a timed event
This is a major change to how the LG client performs it's updates. In the past LG would operate a fixed FPS regardless of incoming update speed and/or frequency. This change allows LG to dynamically increase it's FPS in order to better sync with the guest as it's rate changes.
This commit is contained in:
parent
756b57400b
commit
e31f38eadc
@ -421,7 +421,7 @@ enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture)
|
|||||||
|
|
||||||
if (texture->tex[s.s].sync != 0)
|
if (texture->tex[s.s].sync != 0)
|
||||||
{
|
{
|
||||||
switch(glClientWaitSync(texture->tex[s.s].sync, 0, 0))
|
switch(glClientWaitSync(texture->tex[s.s].sync, 0, 20000000))
|
||||||
{
|
{
|
||||||
case GL_ALREADY_SIGNALED:
|
case GL_ALREADY_SIGNALED:
|
||||||
case GL_CONDITION_SATISFIED:
|
case GL_CONDITION_SATISFIED:
|
||||||
|
@ -62,6 +62,7 @@ static int renderThread(void * unused);
|
|||||||
static int frameThread (void * unused);
|
static int frameThread (void * unused);
|
||||||
|
|
||||||
static LGEvent *e_startup = NULL;
|
static LGEvent *e_startup = NULL;
|
||||||
|
static LGEvent *e_frame = NULL;
|
||||||
static LGThread *t_spice = NULL;
|
static LGThread *t_spice = NULL;
|
||||||
static LGThread *t_render = NULL;
|
static LGThread *t_render = NULL;
|
||||||
static LGThread *t_cursor = NULL;
|
static LGThread *t_cursor = NULL;
|
||||||
@ -149,7 +150,7 @@ static int renderThread(void * unused)
|
|||||||
|
|
||||||
unsigned int resyncCheck = 0;
|
unsigned int resyncCheck = 0;
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
clock_gettime(CLOCK_REALTIME, &time);
|
||||||
|
|
||||||
while(state.running)
|
while(state.running)
|
||||||
{
|
{
|
||||||
@ -161,7 +162,7 @@ static int renderThread(void * unused)
|
|||||||
resyncCheck = 0;
|
resyncCheck = 0;
|
||||||
|
|
||||||
struct timespec tmp;
|
struct timespec tmp;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &tmp);
|
clock_gettime(CLOCK_REALTIME, &tmp);
|
||||||
if (tmp.tv_nsec - time.tv_nsec < 0)
|
if (tmp.tv_nsec - time.tv_nsec < 0)
|
||||||
{
|
{
|
||||||
tmp.tv_sec -= time.tv_sec - 1;
|
tmp.tv_sec -= time.tv_sec - 1;
|
||||||
@ -172,12 +173,6 @@ static int renderThread(void * unused)
|
|||||||
tmp.tv_sec -= time.tv_sec;
|
tmp.tv_sec -= time.tv_sec;
|
||||||
tmp.tv_nsec -= time.tv_nsec;
|
tmp.tv_nsec -= time.tv_nsec;
|
||||||
}
|
}
|
||||||
const unsigned long diff = tmp.tv_sec * 1000000000 + tmp.tv_nsec;
|
|
||||||
if (diff > state.frameTime)
|
|
||||||
{
|
|
||||||
DEBUG_INFO("Timer drift detected, %lu is > %lu", diff, state.frameTime);
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.lgr->render_begin && !state.lgr->render_begin(state.lgrData,
|
if (state.lgr->render_begin && !state.lgr->render_begin(state.lgrData,
|
||||||
@ -227,8 +222,6 @@ static int renderThread(void * unused)
|
|||||||
state.resizeDone = true;
|
state.resizeDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.frameTime > 0)
|
|
||||||
{
|
|
||||||
uint64_t nsec = time.tv_nsec + state.frameTime;
|
uint64_t nsec = time.tv_nsec + state.frameTime;
|
||||||
if(nsec > 1e9)
|
if(nsec > 1e9)
|
||||||
{
|
{
|
||||||
@ -238,8 +231,7 @@ static int renderThread(void * unused)
|
|||||||
else
|
else
|
||||||
time.tv_nsec = nsec;
|
time.tv_nsec = nsec;
|
||||||
|
|
||||||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &time, NULL);
|
lgWaitEventAbs(e_frame, &time);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.running = false;
|
state.running = false;
|
||||||
@ -474,6 +466,7 @@ static int frameThread(void * unused)
|
|||||||
}
|
}
|
||||||
lgmpClientMessageDone(queue);
|
lgmpClientMessageDone(queue);
|
||||||
++state.frameCount;
|
++state.frameCount;
|
||||||
|
lgSignalEvent(e_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
lgmpClientUnsubscribe(&queue);
|
lgmpClientUnsubscribe(&queue);
|
||||||
@ -1443,6 +1436,13 @@ static int lg_run()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup the new frame event
|
||||||
|
if (!(e_frame = lgCreateEvent(true, 0)))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("failed to create the frame event");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// start the renderThread so we don't just display junk
|
// start the renderThread so we don't just display junk
|
||||||
if (!lgCreateThread("renderThread", renderThread, NULL, &t_render))
|
if (!lgCreateThread("renderThread", renderThread, NULL, &t_render))
|
||||||
{
|
{
|
||||||
@ -1555,11 +1555,18 @@ static void lg_shutdown()
|
|||||||
if (t_render)
|
if (t_render)
|
||||||
{
|
{
|
||||||
lgSignalEvent(e_startup);
|
lgSignalEvent(e_startup);
|
||||||
|
lgSignalEvent(e_frame);
|
||||||
lgJoinThread(t_render, NULL);
|
lgJoinThread(t_render, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
lgmpClientFree(&state.lgmp);
|
lgmpClientFree(&state.lgmp);
|
||||||
|
|
||||||
|
if (e_frame)
|
||||||
|
{
|
||||||
|
lgFreeEvent(e_frame);
|
||||||
|
e_frame = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (e_startup)
|
if (e_startup)
|
||||||
{
|
{
|
||||||
lgFreeEvent(e_startup);
|
lgFreeEvent(e_startup);
|
||||||
|
@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#define TIMEOUT_INFINITE ((unsigned int)~0)
|
#define TIMEOUT_INFINITE ((unsigned int)~0)
|
||||||
|
|
||||||
@ -35,3 +36,7 @@ bool lgResetEvent (LGEvent * handle);
|
|||||||
// os specific method to wrap/convert a native event into a LGEvent
|
// os specific method to wrap/convert a native event into a LGEvent
|
||||||
// for windows this is an event HANDLE
|
// for windows this is an event HANDLE
|
||||||
LGEvent * lgWrapEvent(void * handle);
|
LGEvent * lgWrapEvent(void * handle);
|
||||||
|
|
||||||
|
// Posix specific, not implmented/possible in windows
|
||||||
|
bool lgWaitEventAbs(LGEvent * handle, struct timespec * ts);
|
||||||
|
bool lgWaitEventNS (LGEvent * handle, unsigned int timeout);
|
||||||
|
@ -72,7 +72,7 @@ void lgFreeEvent(LGEvent * handle)
|
|||||||
free(handle);
|
free(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lgWaitEvent(LGEvent * handle, unsigned int timeout)
|
bool lgWaitEventAbs(LGEvent * handle, struct timespec * ts)
|
||||||
{
|
{
|
||||||
assert(handle);
|
assert(handle);
|
||||||
|
|
||||||
@ -82,29 +82,32 @@ bool lgWaitEvent(LGEvent * handle, unsigned int timeout)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(!atomic_load(&handle->flag))
|
bool ret = true;
|
||||||
|
while(ret && !atomic_load(&handle->flag))
|
||||||
{
|
{
|
||||||
if (timeout == TIMEOUT_INFINITE)
|
if (!ts)
|
||||||
{
|
{
|
||||||
if (pthread_cond_wait(&handle->cond, &handle->mutex) != 0)
|
if (pthread_cond_wait(&handle->cond, &handle->mutex) != 0)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Wait to wait on the condition");
|
DEBUG_ERROR("Wait to wait on the condition");
|
||||||
return false;
|
ret = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
switch(pthread_cond_timedwait(&handle->cond, &handle->mutex, ts))
|
||||||
ts.tv_sec = timeout / 1000;
|
|
||||||
ts.tv_nsec = (timeout % 1000) * 1000000;
|
|
||||||
switch(pthread_cond_timedwait(&handle->cond, &handle->mutex, &ts))
|
|
||||||
{
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return false;
|
ret = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
ret = false;
|
||||||
DEBUG_ERROR("Timed wait failed");
|
DEBUG_ERROR("Timed wait failed");
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +121,31 @@ bool lgWaitEvent(LGEvent * handle, unsigned int timeout)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lgWaitEventNS(LGEvent * handle, unsigned int timeout)
|
||||||
|
{
|
||||||
|
if (timeout == TIMEOUT_INFINITE)
|
||||||
|
return lgWaitEventAbs(handle, NULL);
|
||||||
|
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
uint64_t nsec = ts.tv_nsec + timeout;
|
||||||
|
if(nsec > 1e9)
|
||||||
|
{
|
||||||
|
ts.tv_nsec = nsec - 1e9;
|
||||||
|
++ts.tv_sec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ts.tv_nsec = nsec;
|
||||||
|
|
||||||
|
return lgWaitEventAbs(handle, &ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lgWaitEvent(LGEvent * handle, unsigned int timeout)
|
||||||
|
{
|
||||||
|
return lgWaitEventNS(handle, timeout * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lgSignalEvent(LGEvent * handle)
|
bool lgSignalEvent(LGEvent * handle)
|
||||||
|
Loading…
Reference in New Issue
Block a user