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;
Eina_Bool locked : 1;
Eina_Bool busy : 1;
Eina_Bool used : 1;
Eina_Bool orphaned : 1;
Eina_Bool alpha : 1;
};

View File

@ -13,8 +13,7 @@ struct _Dmabuf_Surface
Surface *surface;
Ecore_Wl2_Buffer *current;
Ecore_Wl2_Buffer **buffer;
int nbuf;
Eina_List *buffers;
Eina_Bool alpha : 1;
};
@ -25,31 +24,24 @@ static void _evas_dmabuf_surface_destroy(Surface *s);
static void
_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;
int i;
if ((!w) || (!h)) return;
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];
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))
{
b->w = w;
continue;
}
ecore_wl2_buffer_destroy(b);
b->w = w;
continue;
}
buf = ecore_wl2_buffer_create(s->ob->ewd, w, h, surface->alpha);
if (!buf) return;
surface->buffer[i] = buf;
ecore_wl2_buffer_destroy(b);
surface->buffers = eina_list_remove_list(surface->buffers, l);
}
}
@ -83,39 +75,48 @@ _evas_dmabuf_surface_data_get(Surface *s, int *w, int *h)
static Ecore_Wl2_Buffer *
_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 (s->buffer[i]->age > best_age)
if (b->locked || b->busy) continue;
if (b->age > best_age)
{
best = i;
best_age = s->buffer[i]->age;
best = b;
best_age = b->age;
}
}
if (best >= 0) return s->buffer[best];
return NULL;
if (!best && (eina_list_count(s->buffers) < MAX_BUFFERS))
{
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
_evas_dmabuf_surface_assign(Surface *s)
{
Ecore_Wl2_Buffer *b;
Eina_List *l;
Dmabuf_Surface *surface;
int i;
surface = s->surf.dmabuf;
surface->current = _evas_dmabuf_surface_wait(surface);
if (!surface->current)
{
WRN("No free DMAbuf buffers, dropping a frame");
for (i = 0; i < surface->nbuf; i++)
surface->buffer[i]->age = 0;
EINA_LIST_FOREACH(surface->buffers, l, b)
b->age = 0;
return 0;
}
for (i = 0; i < surface->nbuf; i++)
if (surface->buffer[i]->used) surface->buffer[i]->age++;
EINA_LIST_FOREACH(surface->buffers, l, b)
if (b->age) b->age++;
return surface->current->age;
}
@ -135,7 +136,6 @@ _evas_dmabuf_surface_post(Surface *s, Eina_Rectangle *rects, unsigned int count)
surface->current = NULL;
b->busy = EINA_TRUE;
b->used = EINA_TRUE;
b->age = 0;
win = s->info->info.wl2_win;
@ -149,14 +149,11 @@ _evas_dmabuf_surface_post(Surface *s, Eina_Rectangle *rects, unsigned int count)
static void
_internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface)
{
int i;
Ecore_Wl2_Buffer *b;
for (i = 0; i < surface->nbuf; i++)
ecore_wl2_buffer_destroy(surface->buffer[i]);
EINA_LIST_FREE(surface->buffers, b)
ecore_wl2_buffer_destroy(b);
free(surface->buffer);
surface->buffer = NULL;
surface->nbuf = 0;
free(surface);
}
@ -169,12 +166,11 @@ _evas_dmabuf_surface_destroy(Surface *s)
}
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_Buffer_Type types = 0;
Dmabuf_Surface *surf = NULL;
int i = 0;
ewd = s->info->info.wl2_display;
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;
/* 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 (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.reconfigure = _evas_dmabuf_surface_reconfigure;
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;
err:
free(surf->buffer);
free(surf);
return EINA_FALSE;
}

View File

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

View File

@ -10,7 +10,7 @@
#define BLUE_MASK 0x0000ff
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;
@ -19,7 +19,7 @@ _evas_surface_create(Evas_Engine_Info_Wayland *info, int w, int h, Outbuf *ob)
out->info = info;
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);
return NULL;
@ -29,8 +29,6 @@ Outbuf *
_evas_outbuf_setup(int w, int h, Evas_Engine_Info_Wayland *info)
{
Outbuf *ob = NULL;
char *num;
int sw, sh;
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->ewd = info->info.wl2_display;
/* default to triple buffer */
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);
ob->surface = _evas_surface_create(info, ob);
if (!ob->surface) goto surf_err;
unhandled_rotation:
eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8);
return ob;
@ -295,7 +263,6 @@ _evas_outbuf_swap_mode_get(Outbuf *ob)
age = ob->surface->funcs.assign(ob->surface);
if (!age) return MODE_FULL;
if (age > ob->num_buff) return MODE_FULL;
else if (age == 1) return MODE_COPY;
else if (age == 2) return MODE_DOUBLE;
else if (age == 3) return MODE_TRIPLE;