Rework wayland buffer handling

We need to keep wayland buffers around even if they'll never be written
to again.  This is part of Buffer_Reference's task in weston, but we
already have our pixmap abstraction which can serve mostly the same
purpose.

Remove the "buffer reference" stuff from e_pixmap and replace it with a
kept buffer for the last commit.

Add shared memory pool references to keep pools from going away on us.
This commit is contained in:
Derek Foreman 2016-02-16 13:28:10 -06:00 committed by Mike Blumenkrantz
parent b98e78d464
commit dfc7c26ce4
3 changed files with 130 additions and 34 deletions

View File

@ -1696,7 +1696,6 @@ _e_comp_wl_subsurface_destroy(struct wl_resource *resource)
}
_e_comp_wl_surface_state_finish(&sdata->cached);
e_comp_wl_buffer_reference(&sdata->cached_buffer_ref, NULL);
/* the client is getting deleted, which means the pixmap will be getting
* freed. We need to unset the surface user data */
@ -1743,8 +1742,9 @@ _e_comp_wl_subsurface_commit_to_cache(E_Client *ec)
sdata->cached.new_attach = EINA_TRUE;
_e_comp_wl_surface_state_buffer_set(&sdata->cached,
cdata->pending.buffer);
e_comp_wl_buffer_reference(&sdata->cached_buffer_ref,
cdata->pending.buffer);
e_pixmap_resource_set(ec->pixmap, cdata->pending.buffer);
e_pixmap_dirty(ec->pixmap);
e_pixmap_refresh(ec->pixmap);
}
sdata->cached.sx = cdata->pending.sx;

View File

@ -56,7 +56,10 @@ struct _E_Comp_Wl_Buffer
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
struct wl_listener deferred_destroy_listener;
struct wl_shm_buffer *shm_buffer;
struct wl_shm_pool *pool;
E_Pixmap *discarding_pixmap;
int32_t w, h;
uint32_t busy;
};

View File

@ -42,11 +42,13 @@ struct _E_Pixmap
#ifdef HAVE_WAYLAND
E_Comp_Wl_Buffer *buffer;
E_Comp_Wl_Buffer_Ref buffer_ref;
E_Comp_Wl_Buffer *held_buffer;
struct wl_listener buffer_destroy_listener;
struct wl_listener held_buffer_destroy_listener;
void *data;
Eina_Rectangle opaque;
uuid_t uuid;
Eina_List *free_buffers;
#endif
Eina_Bool usable : 1;
@ -55,15 +57,36 @@ struct _E_Pixmap
};
#ifdef HAVE_WAYLAND
static void
_e_pixmap_cb_deferred_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Comp_Wl_Buffer *buffer;
buffer = container_of(listener, E_Comp_Wl_Buffer, deferred_destroy_listener);
buffer->discarding_pixmap->free_buffers = eina_list_remove(buffer->discarding_pixmap->free_buffers, buffer);
buffer->discarding_pixmap = NULL;
}
static void
_e_pixmap_cb_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Pixmap *cp;
cp = container_of(listener, E_Pixmap, buffer_destroy_listener);
cp->data = NULL;
cp->buffer = NULL;
cp->buffer_destroy_listener.notify = NULL;
}
static void
_e_pixmap_cb_held_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
{
E_Pixmap *cp;
cp = container_of(listener, E_Pixmap, held_buffer_destroy_listener);
cp->held_buffer = NULL;
cp->held_buffer_destroy_listener.notify = NULL;
}
#endif
static void
@ -102,6 +125,67 @@ _e_pixmap_image_clear_x(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_U
}
#endif
#ifdef HAVE_WAYLAND
static void
_e_pixmap_wayland_buffer_release(E_Pixmap *cp, E_Comp_Wl_Buffer *buffer)
{
if (!buffer) return;
if (e_comp->rendering)
{
if (buffer->discarding_pixmap) return;
buffer->discarding_pixmap = cp;
buffer->deferred_destroy_listener.notify = _e_pixmap_cb_deferred_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &buffer->deferred_destroy_listener);
cp->free_buffers = eina_list_append(cp->free_buffers, buffer);
return;
}
buffer->busy--;
if (buffer->busy) return;
wl_resource_queue_event(buffer->resource, WL_BUFFER_RELEASE);
wl_shm_pool_unref(buffer->pool);
buffer->pool = NULL;
}
static void
_e_pixmap_wl_buffers_free(E_Pixmap *cp)
{
E_Comp_Wl_Buffer *b;
if (e_comp->rendering) return;
EINA_LIST_FREE(cp->free_buffers, b)
{
wl_list_remove(&b->deferred_destroy_listener.link);
b->deferred_destroy_listener.notify = NULL;
_e_pixmap_wayland_buffer_release(cp, b);
b->discarding_pixmap = NULL;
}
}
static void
_e_pixmap_wayland_image_clear(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
if (!cp->held_buffer) return;
if (!cp->held_buffer->pool) return;
_e_pixmap_wayland_buffer_release(cp, cp->held_buffer);
if (cp->held_buffer_destroy_listener.notify)
{
wl_list_remove(&cp->held_buffer_destroy_listener.link);
cp->held_buffer_destroy_listener.notify = NULL;
}
cp->data = NULL;
cp->held_buffer = NULL;
}
#endif
static void
_e_pixmap_free(E_Pixmap *cp)
{
@ -124,6 +208,7 @@ _e_pixmap_free(E_Pixmap *cp)
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
_e_pixmap_wayland_image_clear(cp);
#endif
break;
default:
@ -546,7 +631,25 @@ e_pixmap_resource_set(E_Pixmap *cp, void *resource)
{
if ((!cp) || (cp->type != E_PIXMAP_TYPE_WL)) return;
#ifdef HAVE_WAYLAND
if (cp->buffer == resource) return;
if (cp->buffer)
{
cp->buffer->busy--;
if (!cp->buffer->busy) wl_resource_queue_event(cp->buffer->resource, WL_BUFFER_RELEASE);
}
if (cp->buffer_destroy_listener.notify)
{
wl_list_remove(&cp->buffer_destroy_listener.link);
cp->buffer_destroy_listener.notify = NULL;
}
cp->buffer = resource;
if (!cp->buffer) return;
cp->buffer_destroy_listener.notify = _e_pixmap_cb_buffer_destroy;
wl_signal_add(&cp->buffer->destroy_signal,
&cp->buffer_destroy_listener);
cp->buffer->busy++;
#else
(void)resource;
#endif
@ -607,7 +710,7 @@ e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache)
#endif
#ifdef HAVE_WAYLAND
if (cp->type == E_PIXMAP_TYPE_WL)
if (!cp->buffer_ref.buffer) return;
if (!cp->buffer) return;
#endif
}
@ -638,6 +741,8 @@ e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache)
struct wl_resource *cb;
Eina_List *free_list;
if (!e_comp->rendering) _e_pixmap_wl_buffers_free(cp);
if ((!cp->client) || (!cp->client->comp_data)) return;
cd = (E_Comp_Wl_Client_Data *)cp->client->comp_data;
@ -652,13 +757,6 @@ e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache)
wl_resource_destroy(cb);
}
}
if (cp->buffer_destroy_listener.notify)
{
wl_list_remove(&cp->buffer_destroy_listener.link);
cp->buffer_destroy_listener.notify = NULL;
}
e_comp_wl_buffer_reference(&cp->buffer_ref, NULL);
cp->data = NULL;
#endif
break;
default:
@ -696,27 +794,22 @@ e_pixmap_image_refresh(E_Pixmap *cp)
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
{
E_Comp_Wl_Buffer *buffer = cp->buffer;
struct wl_shm_buffer *shm_buffer;
if (cp->held_buffer == cp->buffer) return EINA_TRUE;
shm_buffer = buffer->shm_buffer;
if (cp->buffer_ref.buffer && (cp->buffer_ref.buffer != buffer))
{
/* FIXME: wtf? */
}
else if (cp->buffer_ref.buffer) return EINA_TRUE;
e_comp_wl_buffer_reference(&cp->buffer_ref, buffer);
if (cp->held_buffer) _e_pixmap_wayland_image_clear(cp);
if (cp->buffer_destroy_listener.notify)
{
wl_list_remove(&cp->buffer_destroy_listener.link);
cp->buffer_destroy_listener.notify = NULL;
}
if (!cp->buffer->shm_buffer) return EINA_TRUE;
cp->buffer_destroy_listener.notify = _e_pixmap_cb_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &cp->buffer_destroy_listener);
if (shm_buffer)
cp->data = wl_shm_buffer_get_data(shm_buffer);
cp->held_buffer = cp->buffer;
if (!cp->held_buffer) return EINA_TRUE;
cp->held_buffer->pool = wl_shm_buffer_ref_pool(cp->held_buffer->shm_buffer);
cp->held_buffer->busy++;
cp->data = wl_shm_buffer_get_data(cp->buffer->shm_buffer);
cp->held_buffer_destroy_listener.notify = _e_pixmap_cb_held_buffer_destroy;
wl_signal_add(&cp->held_buffer->destroy_signal,
&cp->held_buffer_destroy_listener);
return EINA_TRUE;
}
#endif
@ -757,7 +850,7 @@ e_pixmap_image_is_argb(const E_Pixmap *cp)
#endif
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
return ((cp->buffer_ref.buffer != NULL) && (cp->image_argb));
return ((cp->buffer != NULL) && (cp->image_argb));
#endif
default: break;
}
@ -809,14 +902,14 @@ e_pixmap_image_data_argb_convert(E_Pixmap *cp, void *pix, void *ipix, Eina_Recta
case E_PIXMAP_TYPE_WL:
if (cp->image_argb) return EINA_TRUE;
#ifdef HAVE_WAYLAND
if (cp->buffer_ref.buffer)
if (cp->buffer)
{
struct wl_shm_buffer *shm_buffer;
uint32_t format;
int i, x, y;
unsigned int *src, *dst;
shm_buffer = cp->buffer_ref.buffer->shm_buffer;
shm_buffer = cp->buffer->shm_buffer;
if (!shm_buffer) return EINA_FALSE;
format = wl_shm_buffer_get_format(shm_buffer);