ecore_evas_drm: Calculate gpu blank time offset once at startup

So vmware's graphics driver reports the MONOTONIC drm cap, yet uses
CLOCK_REALTIME instead.  This leaves us with a gigantic offset between the
gpu timestamp and the times ecore_time_get() gets from CLOCK_MONOTONIC.

Since ticking screws directly with loop time this results in some long
distance clock jumping.

This commit fixes drm/gl_drm operation under vmware.
This commit is contained in:
Derek Foreman 2017-07-28 15:24:30 -05:00
parent 0584fc81a2
commit 2b16fc4278
1 changed files with 34 additions and 1 deletions

View File

@ -54,6 +54,7 @@ typedef struct _Ecore_Evas_Engine_Drm_Data
int x, y, w, h;
int depth, bpp;
unsigned int format;
double offset;
Ecore_Drm2_Context ctx;
Ecore_Fd_Handler *hdlr;
Ecore_Drm2_Device *dev;
@ -61,6 +62,7 @@ typedef struct _Ecore_Evas_Engine_Drm_Data
Evas_Device *seat;
Eina_Bool pending : 1;
Eina_Bool ticking : 1;
Eina_Bool once : 1;
} Ecore_Evas_Engine_Drm_Data;
static int _drm_init_count = 0;
@ -623,7 +625,8 @@ _cb_pageflip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int se
{
double t = (double)sec + ((double)usec / 1000000);
ecore_evas_animator_tick(ee, NULL, t);
if (!edata->once) t = ecore_time_get();
ecore_evas_animator_tick(ee, NULL, t - edata->offset);
}
else if (ret)
{
@ -650,13 +653,43 @@ _drm_evas_changed(Ecore_Evas *ee, Eina_Bool changed)
static void
_drm_animator_register(Ecore_Evas *ee)
{
double t;
long sec, usec;
Ecore_Evas_Engine_Drm_Data *edata;
Eina_Bool r;
if (ee->manual_render)
ERR("Attempt to schedule tick for manually rendered canvas");
edata = ee->engine.data;
edata->ticking = EINA_TRUE;
/* Some graphics stacks appear to lie about their clock sources
* so attempt to measure the difference between our clock and the
* GPU's source of timestamps once at startup and apply that.
* If it's tiny, just assume they're the same clock and it's
* measurement error.
*
* <cedric> what happen when you suspend ?
* <cedric> what about drift ?
*
* If someone could relay the message to cedric that I'm not
* talking to him anymore, that would be helpful.
*/
if (!edata->once)
{
r = ecore_drm2_output_blanktime_get(edata->output, 1, &sec, &usec);
if (r)
{
t = (double)sec + ((double)usec / 1000000.0);
edata->offset = t - ecore_time_get();
if (fabs(edata->offset) < 0.010)
edata->offset = 0.0;
edata->once = EINA_TRUE;
}
}
if (!edata->pending && !ee->in_async_render)
{
edata->pending = EINA_TRUE;