wayland_shm: Don't use a fixed number of buffers

We no longer allocate 3 buffers at startup, we now allocate only as needed.

Trimming the queue will come later, as there are some situations where we
might need 3 buffers and later drop down to 2 (when on a hardware plane)

Most clients will only ever need 2 buffers, so this is a reasonable RAM
savings.
This commit is contained in:
Derek Foreman 2017-11-17 14:32:30 -06:00
parent 04ce069cba
commit 796de8cb86
4 changed files with 42 additions and 102 deletions

View File

@ -376,7 +376,6 @@ struct _Ecore_Wl2_Buffer
int index; int index;
Eina_Bool locked : 1; Eina_Bool locked : 1;
Eina_Bool busy : 1; Eina_Bool busy : 1;
Eina_Bool used : 1;
Eina_Bool orphaned : 1; Eina_Bool orphaned : 1;
Eina_Bool alpha : 1; Eina_Bool alpha : 1;
}; };

View File

@ -13,8 +13,7 @@ struct _Dmabuf_Surface
Surface *surface; Surface *surface;
Ecore_Wl2_Buffer *current; Ecore_Wl2_Buffer *current;
Ecore_Wl2_Buffer **buffer; Eina_List *buffers;
int nbuf;
Eina_Bool alpha : 1; Eina_Bool alpha : 1;
}; };
@ -25,31 +24,24 @@ static void _evas_dmabuf_surface_destroy(Surface *s);
static void static void
_evas_dmabuf_surface_reconfigure(Surface *s, int w, int h, uint32_t flags EINA_UNUSED, Eina_Bool force) _evas_dmabuf_surface_reconfigure(Surface *s, int w, int h, uint32_t flags EINA_UNUSED, Eina_Bool force)
{ {
Ecore_Wl2_Buffer *buf; Ecore_Wl2_Buffer *b;
Eina_List *l, *tmp;
Dmabuf_Surface *surface; Dmabuf_Surface *surface;
int i;
if ((!w) || (!h)) return; if ((!w) || (!h)) return;
surface = s->surf.dmabuf; surface = s->surf.dmabuf;
for (i = 0; i < surface->nbuf; i++) EINA_LIST_FOREACH_SAFE(surface->buffers, l, tmp, b)
{ {
if (surface->buffer[i]) int stride = b->stride;
/* If stride is a little bigger than width we still fit */
if (!force && (w >= b->w) && (w <= stride / 4) && (h == b->h))
{ {
Ecore_Wl2_Buffer *b = surface->buffer[i]; b->w = w;
int stride = b->stride; continue;
/* If stride is a little bigger than width we still fit */
if (!force && (w >= b->w) && (w <= stride / 4) && (h == b->h))
{
b->w = w;
continue;
}
ecore_wl2_buffer_destroy(b);
} }
buf = ecore_wl2_buffer_create(s->ob->ewd, w, h, surface->alpha); ecore_wl2_buffer_destroy(b);
if (!buf) return; surface->buffers = eina_list_remove_list(surface->buffers, l);
surface->buffer[i] = buf;
} }
} }
@ -83,39 +75,48 @@ _evas_dmabuf_surface_data_get(Surface *s, int *w, int *h)
static Ecore_Wl2_Buffer * static Ecore_Wl2_Buffer *
_evas_dmabuf_surface_wait(Dmabuf_Surface *s) _evas_dmabuf_surface_wait(Dmabuf_Surface *s)
{ {
int i = 0, best = -1, best_age = -1; Ecore_Wl2_Buffer *b, *best = NULL;
Eina_List *l;
int best_age = -1;
for (i = 0; i < s->nbuf; i++) EINA_LIST_FOREACH(s->buffers, l, b)
{ {
if (s->buffer[i]->locked || s->buffer[i]->busy) continue; if (b->locked || b->busy) continue;
if (s->buffer[i]->age > best_age) if (b->age > best_age)
{ {
best = i; best = b;
best_age = s->buffer[i]->age; best_age = b->age;
} }
} }
if (best >= 0) return s->buffer[best]; if (!best && (eina_list_count(s->buffers) < MAX_BUFFERS))
return NULL; {
Outbuf *ob;
ob = s->surface->ob;
best = ecore_wl2_buffer_create(ob->ewd, ob->w, ob->h, s->alpha);
s->buffers = eina_list_append(s->buffers, best);
}
return best;
} }
static int static int
_evas_dmabuf_surface_assign(Surface *s) _evas_dmabuf_surface_assign(Surface *s)
{ {
Ecore_Wl2_Buffer *b;
Eina_List *l;
Dmabuf_Surface *surface; Dmabuf_Surface *surface;
int i;
surface = s->surf.dmabuf; surface = s->surf.dmabuf;
surface->current = _evas_dmabuf_surface_wait(surface); surface->current = _evas_dmabuf_surface_wait(surface);
if (!surface->current) if (!surface->current)
{ {
WRN("No free DMAbuf buffers, dropping a frame"); WRN("No free DMAbuf buffers, dropping a frame");
for (i = 0; i < surface->nbuf; i++) EINA_LIST_FOREACH(surface->buffers, l, b)
surface->buffer[i]->age = 0; b->age = 0;
return 0; return 0;
} }
for (i = 0; i < surface->nbuf; i++) EINA_LIST_FOREACH(surface->buffers, l, b)
if (surface->buffer[i]->used) surface->buffer[i]->age++; if (b->age) b->age++;
return surface->current->age; return surface->current->age;
} }
@ -135,7 +136,6 @@ _evas_dmabuf_surface_post(Surface *s, Eina_Rectangle *rects, unsigned int count)
surface->current = NULL; surface->current = NULL;
b->busy = EINA_TRUE; b->busy = EINA_TRUE;
b->used = EINA_TRUE;
b->age = 0; b->age = 0;
win = s->info->info.wl2_win; win = s->info->info.wl2_win;
@ -149,14 +149,11 @@ _evas_dmabuf_surface_post(Surface *s, Eina_Rectangle *rects, unsigned int count)
static void static void
_internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface) _internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface)
{ {
int i; Ecore_Wl2_Buffer *b;
for (i = 0; i < surface->nbuf; i++) EINA_LIST_FREE(surface->buffers, b)
ecore_wl2_buffer_destroy(surface->buffer[i]); ecore_wl2_buffer_destroy(b);
free(surface->buffer);
surface->buffer = NULL;
surface->nbuf = 0;
free(surface); free(surface);
} }
@ -169,12 +166,11 @@ _evas_dmabuf_surface_destroy(Surface *s)
} }
Eina_Bool Eina_Bool
_evas_dmabuf_surface_create(Surface *s, int w, int h, int num_buff) _evas_dmabuf_surface_create(Surface *s)
{ {
Ecore_Wl2_Display *ewd; Ecore_Wl2_Display *ewd;
Ecore_Wl2_Buffer_Type types = 0; Ecore_Wl2_Buffer_Type types = 0;
Dmabuf_Surface *surf = NULL; Dmabuf_Surface *surf = NULL;
int i = 0;
ewd = s->info->info.wl2_display; ewd = s->info->info.wl2_display;
if (ecore_wl2_display_shm_get(ewd)) if (ecore_wl2_display_shm_get(ewd))
@ -189,27 +185,8 @@ _evas_dmabuf_surface_create(Surface *s, int w, int h, int num_buff)
surf->alpha = s->info->info.destination_alpha; surf->alpha = s->info->info.destination_alpha;
/* create surface buffers */ /* create surface buffers */
surf->nbuf = num_buff;
surf->buffer = calloc(surf->nbuf, sizeof(Ecore_Wl2_Buffer *));
if (!surf->buffer) goto err;
if (!ecore_wl2_buffer_init(ewd, types)) goto err; if (!ecore_wl2_buffer_init(ewd, types)) goto err;
if (w && h)
{
for (i = 0; i < num_buff; i++)
{
surf->buffer[i] = ecore_wl2_buffer_create(s->ob->ewd,
w, h, surf->alpha);
if (!surf->buffer[i])
{
DBG("Could not create buffers");
/* _init() handled surface cleanup when it failed */
return EINA_FALSE;
}
}
}
s->funcs.destroy = _evas_dmabuf_surface_destroy; s->funcs.destroy = _evas_dmabuf_surface_destroy;
s->funcs.reconfigure = _evas_dmabuf_surface_reconfigure; s->funcs.reconfigure = _evas_dmabuf_surface_reconfigure;
s->funcs.data_get = _evas_dmabuf_surface_data_get; s->funcs.data_get = _evas_dmabuf_surface_data_get;
@ -219,7 +196,6 @@ _evas_dmabuf_surface_create(Surface *s, int w, int h, int num_buff)
return EINA_TRUE; return EINA_TRUE;
err: err:
free(surf->buffer);
free(surf); free(surf);
return EINA_FALSE; return EINA_FALSE;
} }

View File

@ -100,7 +100,6 @@ struct _Outbuf
int w, h; int w, h;
int rotation; int rotation;
int onebuf; int onebuf;
int num_buff;
Outbuf_Depth depth; Outbuf_Depth depth;
Ecore_Wl2_Display *ewd; Ecore_Wl2_Display *ewd;
@ -130,8 +129,7 @@ struct _Outbuf
Eina_Bool dirty : 1; Eina_Bool dirty : 1;
}; };
Eina_Bool _evas_dmabuf_surface_create(Surface *s, int w, int h, int num_buff); Eina_Bool _evas_dmabuf_surface_create(Surface *s);
Eina_Bool _evas_shm_surface_create(Surface *s, int w, int h, int num_buff);
Outbuf *_evas_outbuf_setup(int w, int h, Evas_Engine_Info_Wayland *info); Outbuf *_evas_outbuf_setup(int w, int h, Evas_Engine_Info_Wayland *info);
void _evas_outbuf_free(Outbuf *ob); void _evas_outbuf_free(Outbuf *ob);

View File

@ -10,7 +10,7 @@
#define BLUE_MASK 0x0000ff #define BLUE_MASK 0x0000ff
static Surface * static Surface *
_evas_surface_create(Evas_Engine_Info_Wayland *info, int w, int h, Outbuf *ob) _evas_surface_create(Evas_Engine_Info_Wayland *info, Outbuf *ob)
{ {
Surface *out; Surface *out;
@ -19,7 +19,7 @@ _evas_surface_create(Evas_Engine_Info_Wayland *info, int w, int h, Outbuf *ob)
out->info = info; out->info = info;
out->ob = ob; out->ob = ob;
if (_evas_dmabuf_surface_create(out, w, h, ob->num_buff)) return out; if (_evas_dmabuf_surface_create(out)) return out;
free(out); free(out);
return NULL; return NULL;
@ -29,8 +29,6 @@ Outbuf *
_evas_outbuf_setup(int w, int h, Evas_Engine_Info_Wayland *info) _evas_outbuf_setup(int w, int h, Evas_Engine_Info_Wayland *info)
{ {
Outbuf *ob = NULL; Outbuf *ob = NULL;
char *num;
int sw, sh;
LOGFN(__FILE__, __LINE__, __FUNCTION__); LOGFN(__FILE__, __LINE__, __FUNCTION__);
@ -46,39 +44,9 @@ _evas_outbuf_setup(int w, int h, Evas_Engine_Info_Wayland *info)
ob->priv.destination_alpha = info->info.destination_alpha; ob->priv.destination_alpha = info->info.destination_alpha;
ob->ewd = info->info.wl2_display; ob->ewd = info->info.wl2_display;
/* default to triple buffer */ ob->surface = _evas_surface_create(info, ob);
ob->num_buff = 3;
/* check for any 'number of buffers' override in the environment */
if ((num = getenv("EVAS_WAYLAND_SHM_BUFFERS")))
{
int n = 0;
n = atoi(num);
if (n <= 0) n = 1;
if (n > MAX_BUFFERS) n = MAX_BUFFERS;
ob->num_buff = n;
}
/* try to create the outbuf surface */
if ((ob->rotation == 0) || (ob->rotation == 180))
{
sw = w;
sh = h;
}
else if ((ob->rotation == 90) || (ob->rotation == 270))
{
sw = h;
sh = w;
}
else
goto unhandled_rotation;
ob->surface = _evas_surface_create(info, sw, sh, ob);
if (!ob->surface) goto surf_err; if (!ob->surface) goto surf_err;
unhandled_rotation:
eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8); eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8);
return ob; return ob;
@ -295,7 +263,6 @@ _evas_outbuf_swap_mode_get(Outbuf *ob)
age = ob->surface->funcs.assign(ob->surface); age = ob->surface->funcs.assign(ob->surface);
if (!age) return MODE_FULL; if (!age) return MODE_FULL;
if (age > ob->num_buff) return MODE_FULL;
else if (age == 1) return MODE_COPY; else if (age == 1) return MODE_COPY;
else if (age == 2) return MODE_DOUBLE; else if (age == 2) return MODE_DOUBLE;
else if (age == 3) return MODE_TRIPLE; else if (age == 3) return MODE_TRIPLE;