forked from enlightenment/efl
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:
parent
95ae131502
commit
745de87c78
|
@ -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_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_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_flush(Outbuf *ob, Tilebuf_Rect *surface_damage, Tilebuf_Rect *buffer_damage, Evas_Render_Mode render_mode);
|
||||||
void _outbuf_redraws_clear(Outbuf *ob);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,26 +8,6 @@
|
||||||
#define MAX_BUFFERS 10
|
#define MAX_BUFFERS 10
|
||||||
#define QUEUE_TRIM_DURATION 100
|
#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 *
|
static Outbuf_Fb *
|
||||||
_outbuf_fb_create(Outbuf *ob, int w, int h)
|
_outbuf_fb_create(Outbuf *ob, int w, int h)
|
||||||
{
|
{
|
||||||
|
@ -65,6 +45,126 @@ _outbuf_fb_destroy(Outbuf_Fb *ofb)
|
||||||
free(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 *
|
||||||
_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
|
_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +228,6 @@ _outbuf_rotation_get(Outbuf *ob)
|
||||||
void
|
void
|
||||||
_outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
|
_outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
|
||||||
{
|
{
|
||||||
Outbuf_Fb *ofb;
|
|
||||||
unsigned int format = DRM_FORMAT_ARGB8888;
|
unsigned int format = DRM_FORMAT_ARGB8888;
|
||||||
|
|
||||||
switch (depth)
|
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))
|
(ob->depth == depth) && (ob->format == format))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
while (ecore_drm2_fb_release(ob->priv.output, EINA_TRUE));
|
||||||
|
|
||||||
ob->w = w;
|
ob->w = w;
|
||||||
ob->h = h;
|
ob->h = h;
|
||||||
ob->depth = depth;
|
ob->depth = depth;
|
||||||
|
@ -181,112 +282,15 @@ _outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
|
||||||
ob->rotation = rotation;
|
ob->rotation = rotation;
|
||||||
ob->priv.unused_duration = 0;
|
ob->priv.unused_duration = 0;
|
||||||
|
|
||||||
EINA_LIST_FREE(ob->priv.fb_list, ofb)
|
|
||||||
_outbuf_fb_destroy(ofb);
|
|
||||||
|
|
||||||
/* TODO: idle flush */
|
/* 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
|
Render_Output_Swap_Mode
|
||||||
_outbuf_state_get(Outbuf *ob)
|
_outbuf_state_get(Outbuf *ob)
|
||||||
{
|
{
|
||||||
int age;
|
int age;
|
||||||
|
|
||||||
if (!_outbuf_fb_assign(ob)) return MODE_FULL;
|
if (!ob->priv.draw) return MODE_FULL;
|
||||||
|
|
||||||
age = ob->priv.draw->age;
|
age = ob->priv.draw->age;
|
||||||
if (age > 4) return MODE_FULL;
|
if (age > 4) return MODE_FULL;
|
||||||
|
@ -538,14 +542,6 @@ _outbuf_flush(Outbuf *ob, Tilebuf_Rect *surface_damage EINA_UNUSED, Tilebuf_Rect
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
_outbuf_buffer_swap(ob);
|
||||||
_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;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue