evas drm: Fix software output rotation

Summary:
Don't use redraws_clear to handle buffer swapping. Buffer swapping
should be done on outbuf_flush. This patch fixes evas drm software
output rotation (along with other patches in the series).

ref T7690

@fix
Depends on D8402

Reviewers: raster, cedric, zmike

Subscribers: #reviewers, #committers

Tags: #efl

Maniphest Tasks: T7690

Differential Revision: https://phab.enlightenment.org/D8403
This commit is contained in:
Christopher Michael 2019-03-22 12:41:43 -04:00
parent 95ae131502
commit 745de87c78
2 changed files with 124 additions and 129 deletions

View File

@ -82,6 +82,5 @@ Render_Output_Swap_Mode _outbuf_state_get(Outbuf *ob);
void *_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
void _outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
void _outbuf_flush(Outbuf *ob, Tilebuf_Rect *surface_damage, Tilebuf_Rect *buffer_damage, Evas_Render_Mode render_mode);
void _outbuf_redraws_clear(Outbuf *ob);
#endif

View File

@ -8,26 +8,6 @@
#define MAX_BUFFERS 10
#define QUEUE_TRIM_DURATION 100
static void
_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
{
/* Ecore_Drm2_Plane *plane; */
Outbuf_Fb *ofb;
ofb = ob->priv.draw;
if (!ofb) return;
ecore_drm2_fb_dirty(ofb->fb, rects, count);
if (!ob->priv.plane)
ob->priv.plane = ecore_drm2_plane_assign(ob->priv.output, ofb->fb, 0, 0);
else ecore_drm2_plane_fb_set(ob->priv.plane, ofb->fb);
ecore_drm2_fb_flip(ofb->fb, ob->priv.output);
ofb->drawn = EINA_TRUE;
ofb->age = 0;
}
static Outbuf_Fb *
_outbuf_fb_create(Outbuf *ob, int w, int h)
{
@ -65,6 +45,126 @@ _outbuf_fb_destroy(Outbuf_Fb *ofb)
free(ofb);
}
static Outbuf_Fb *
_outbuf_fb_wait(Outbuf *ob)
{
Eina_List *l;
Outbuf_Fb *ofb, *best = NULL;
int best_age = -1, num_required = 1, num_allocated = 0;
/* We pick the oldest available buffer to avoid using the same two
* repeatedly and then having the third be stale when we need it
*/
EINA_LIST_FOREACH(ob->priv.fb_list, l, ofb)
{
num_allocated++;
if (ecore_drm2_fb_busy_get(ofb->fb))
{
num_required++;
continue;
}
if (ofb->valid && (ofb->age > best_age))
{
best = ofb;
best_age = best->age;
}
}
if (num_required < num_allocated)
ob->priv.unused_duration++;
else
ob->priv.unused_duration = 0;
/* If we've had unused buffers for longer than QUEUE_TRIM_DURATION, then
* destroy the oldest buffer (currently in best) and recursively call
* ourself to get the next oldest.
*/
if (best && (ob->priv.unused_duration > QUEUE_TRIM_DURATION))
{
ob->priv.unused_duration = 0;
ob->priv.fb_list = eina_list_remove(ob->priv.fb_list, best);
_outbuf_fb_destroy(best);
best = _outbuf_fb_wait(ob);
}
return best;
}
static Outbuf_Fb *
_outbuf_fb_assign(Outbuf *ob)
{
int fw = 0, fh = 0;
Outbuf_Fb *ofb;
Eina_List *l;
ob->priv.draw = _outbuf_fb_wait(ob);
if (!ob->priv.draw)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(eina_list_count(ob->priv.fb_list) >= MAX_BUFFERS, NULL);
if ((ob->rotation == 0) || (ob->rotation == 180))
{
fw = ob->w;
fh = ob->h;
}
else if ((ob->rotation == 90) || (ob->rotation == 270))
{
fw = ob->h;
fh = ob->w;
}
ob->priv.draw = _outbuf_fb_create(ob, fw, fh);
if (ob->priv.draw)
ob->priv.fb_list = eina_list_append(ob->priv.fb_list, ob->priv.draw);
}
while (!ob->priv.draw)
{
ecore_drm2_fb_release(ob->priv.output, EINA_TRUE);
ob->priv.draw = _outbuf_fb_wait(ob);
}
EINA_LIST_FOREACH(ob->priv.fb_list, l, ofb)
{
if ((ofb->valid) && (ofb->drawn))
{
ofb->age++;
if (ofb->age > 4)
{
ofb->age = 0;
ofb->drawn = EINA_FALSE;
}
}
}
return ob->priv.draw;
}
static void
_outbuf_buffer_swap(Outbuf *ob)
{
Outbuf_Fb *ofb;
ofb = ob->priv.draw;
if (!ofb)
{
ecore_drm2_fb_release(ob->priv.output, EINA_TRUE);
ofb = _outbuf_fb_assign(ob);
if (!ofb)
{
ERR("Could not assign front buffer");
return;
}
}
if (!ob->priv.plane)
ob->priv.plane = ecore_drm2_plane_assign(ob->priv.output, ofb->fb, 0, 0);
else ecore_drm2_plane_fb_set(ob->priv.plane, ofb->fb);
ecore_drm2_fb_flip(ofb->fb, ob->priv.output);
ofb->drawn = EINA_TRUE;
ofb->age = 0;
}
Outbuf *
_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
{
@ -128,7 +228,6 @@ _outbuf_rotation_get(Outbuf *ob)
void
_outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
{
Outbuf_Fb *ofb;
unsigned int format = DRM_FORMAT_ARGB8888;
switch (depth)
@ -174,6 +273,8 @@ _outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
(ob->depth == depth) && (ob->format == format))
return;
while (ecore_drm2_fb_release(ob->priv.output, EINA_TRUE));
ob->w = w;
ob->h = h;
ob->depth = depth;
@ -181,112 +282,15 @@ _outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
ob->rotation = rotation;
ob->priv.unused_duration = 0;
EINA_LIST_FREE(ob->priv.fb_list, ofb)
_outbuf_fb_destroy(ofb);
/* TODO: idle flush */
}
static Outbuf_Fb *
_outbuf_fb_wait(Outbuf *ob)
{
Eina_List *l;
Outbuf_Fb *ofb, *best = NULL;
int best_age = -1, num_required = 1, num_allocated = 0;
/* We pick the oldest available buffer to avoid using the same two
* repeatedly and then having the third be stale when we need it
*/
EINA_LIST_FOREACH(ob->priv.fb_list, l, ofb)
{
num_allocated++;
if (ecore_drm2_fb_busy_get(ofb->fb))
{
num_required++;
continue;
}
if (ofb->valid && (ofb->age > best_age))
{
best = ofb;
best_age = best->age;
}
}
if (num_required < num_allocated)
ob->priv.unused_duration++;
else
ob->priv.unused_duration = 0;
/* If we've had unused buffers for longer than QUEUE_TRIM_DURATION, then
* destroy the oldest buffer (currently in best) and recursively call
* ourself to get the next oldest.
*/
if (best && (ob->priv.unused_duration > QUEUE_TRIM_DURATION))
{
ob->priv.unused_duration = 0;
ob->priv.fb_list = eina_list_remove(ob->priv.fb_list, best);
_outbuf_fb_destroy(best);
best = _outbuf_fb_wait(ob);
}
return best;
}
static Eina_Bool
_outbuf_fb_assign(Outbuf *ob)
{
int fw = 0, fh = 0;
Outbuf_Fb *ofb;
Eina_List *l;
ob->priv.draw = _outbuf_fb_wait(ob);
if (!ob->priv.draw)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(eina_list_count(ob->priv.fb_list) >= MAX_BUFFERS, EINA_FALSE);
if ((ob->rotation == 0) || (ob->rotation == 180))
{
fw = ob->w;
fh = ob->h;
}
else if ((ob->rotation == 90) || (ob->rotation == 270))
{
fw = ob->h;
fh = ob->w;
}
ob->priv.draw = _outbuf_fb_create(ob, fw, fh);
if (ob->priv.draw)
ob->priv.fb_list = eina_list_append(ob->priv.fb_list, ob->priv.draw);
}
while (!ob->priv.draw)
{
ecore_drm2_fb_release(ob->priv.output, EINA_TRUE);
ob->priv.draw = _outbuf_fb_wait(ob);
}
EINA_LIST_FOREACH(ob->priv.fb_list, l, ofb)
{
if ((ofb->valid) && (ofb->drawn))
{
ofb->age++;
if (ofb->age > 4)
{
ofb->age = 0;
ofb->drawn = EINA_FALSE;
}
}
}
return EINA_TRUE;
}
Render_Output_Swap_Mode
_outbuf_state_get(Outbuf *ob)
{
int age;
if (!_outbuf_fb_assign(ob)) return MODE_FULL;
if (!ob->priv.draw) return MODE_FULL;
age = ob->priv.draw->age;
if (age > 4) return MODE_FULL;
@ -538,14 +542,6 @@ _outbuf_flush(Outbuf *ob, Tilebuf_Rect *surface_damage EINA_UNUSED, Tilebuf_Rect
i++;
}
}
void
_outbuf_redraws_clear(Outbuf *ob)
{
if (!ob->priv.rect_count) return;
_outbuf_buffer_swap(ob, ob->priv.rects, ob->priv.rect_count);
free(ob->priv.rects);
ob->priv.rect_count = 0;
_outbuf_buffer_swap(ob);
}