You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1340 lines
32 KiB

#include "e.h"
#ifdef HAVE_WAYLAND
# include "e_comp_wl.h"
# ifndef EGL_TEXTURE_FORMAT
# define EGL_TEXTURE_FORMAT 0x3080
# endif
# ifndef EGL_TEXTURE_RGBA
# define EGL_TEXTURE_RGBA 0x305E
# endif
# ifndef DRM_FORMAT_ARGB8888
# define DRM_FORMAT_ARGB8888 0x34325241
# define DRM_FORMAT_XRGB8888 0x34325258
# endif
#endif
#ifndef HAVE_WAYLAND_ONLY
# include "e_comp_x.h"
#endif
#include <sys/mman.h>
static Eina_Hash *pixmaps[2] = {NULL};
static Eina_Hash *aliases[2] = {NULL};
struct _E_Pixmap
{
unsigned int refcount;
unsigned int failures;
E_Client *client;
E_Pixmap_Type type;
int64_t win;
int64_t alias;
Ecore_Window parent;
int w, h;
#ifndef HAVE_WAYLAND_ONLY
void *image;
void *visual;
int ibpp, ibpl;
unsigned int cmap;
uint32_t pixmap;
Eina_List *images_cache;
#endif
#ifdef HAVE_WAYLAND
E_Comp_Wl_Buffer *buffer;
E_Comp_Wl_Buffer *held_buffer;
struct wl_listener buffer_destroy_listener;
struct wl_listener held_buffer_destroy_listener;
void *data;
Eina_Rectangle opaque;
Eina_List *free_buffers;
Eina_List *busy_list;
#endif
Eina_Bool usable E_BITFIELD;
Eina_Bool dirty E_BITFIELD;
Eina_Bool image_argb E_BITFIELD;
};
#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->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
_e_pixmap_clear(E_Pixmap *cp, Eina_Bool cache)
{
cp->w = cp->h = 0;
cp->image_argb = EINA_FALSE;
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if (cp->pixmap)
{
ecore_x_pixmap_free(cp->pixmap);
cp->pixmap = 0;
ecore_x_e_comp_pixmap_set(cp->parent ?: (Ecore_X_Window)cp->win, 0);
e_pixmap_image_clear(cp, cache);
}
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
e_pixmap_image_clear(cp, cache);
#endif
break;
default:
break;
}
}
#ifndef HAVE_WAYLAND_ONLY
static void
_e_pixmap_image_clear_x(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Eina_List *list = data;
E_FREE_LIST(list, ecore_x_image_free);
}
#endif
#ifdef HAVE_WAYLAND
static void
_e_pixmap_wl_resource_release(E_Comp_Wl_Buffer *buffer)
{
buffer->busy--;
if (buffer->dmabuf_buffer)
linux_dmabuf_buffer_unref(buffer->dmabuf_buffer);
if (buffer->busy) return;
if (buffer->pool)
{
wl_shm_pool_unref(buffer->pool);
buffer->pool = NULL;
}
if (buffer->destroyed)
{
free(buffer);
return;
}
wl_buffer_send_release(buffer->resource);
}
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;
}
if (buffer->busy == 1)
{
// we are at busy 1 abut about to go to 0 below, so remove now
cp->busy_list = eina_list_remove(cp->busy_list, buffer);
}
_e_pixmap_wl_resource_release(buffer);
}
static void
_e_pixmap_wl_buffers_free(E_Pixmap *cp)
{
E_Comp_Wl_Buffer *b;
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->busy_list)
{
E_Comp_Wl_Buffer *buffer;
EINA_LIST_FREE(cp->busy_list, buffer)
{
buffer->busy--;
if (buffer->dmabuf_buffer)
linux_dmabuf_buffer_unref(buffer->dmabuf_buffer);
}
}
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)
{
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if (!cp->images_cache) break;
if (cp->client)
evas_object_event_callback_add(cp->client->frame,
EVAS_CALLBACK_FREE,
_e_pixmap_image_clear_x,
cp->images_cache);
else
{
void *i;
EINA_LIST_FREE(cp->images_cache, i)
ecore_job_add((Ecore_Cb)ecore_x_image_free, i);
}
cp->images_cache = NULL;
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
_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;
}
#endif
break;
default:
break;
}
_e_pixmap_clear(cp, 1);
free(cp);
}
static E_Pixmap *
_e_pixmap_new(E_Pixmap_Type type)
{
E_Pixmap *cp;
cp = E_NEW(E_Pixmap, 1);
cp->type = type;
cp->w = cp->h = 0;
cp->refcount = 1;
cp->dirty = 1;
return cp;
}
static E_Pixmap *
_e_pixmap_find(E_Pixmap_Type type, va_list *l)
{
#ifndef HAVE_WAYLAND_ONLY
Ecore_X_Window xwin;
#endif
#ifdef HAVE_WAYLAND
int64_t id;
#endif
E_Pixmap *cp;
if (!pixmaps[type]) return NULL;
switch (type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
xwin = va_arg(*l, uint32_t);
cp = eina_hash_find(aliases[type], &xwin);
if (!cp) cp = eina_hash_find(pixmaps[type], &xwin);
return cp;
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
id = va_arg(*l, int64_t);
cp = eina_hash_find(aliases[type], &id);
if (!cp) cp = eina_hash_find(pixmaps[type], &id);
return cp;
#endif
break;
default: break;
}
return NULL;
}
E_API int
e_pixmap_free(E_Pixmap *cp)
{
#ifndef HAVE_WAYLAND_ONLY
Ecore_X_Window xwin = cp ? cp->win : 0;
Ecore_X_Window alias_xwin = cp ? cp->alias : 0;
#endif
#ifdef HAVE_WAYLAND
int64_t id = cp ? cp->win : 0;
int64_t alias_id = cp ? cp->alias : 0;
#endif
E_Pixmap_Type type;
if (!cp) return 0;
if (--cp->refcount) return cp->refcount;
type = cp->type;
e_pixmap_image_clear(cp, EINA_FALSE);
switch (type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if (alias_xwin) eina_hash_del(aliases[type], &alias_xwin, cp);
eina_hash_del(pixmaps[type], &xwin, cp);
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
if (alias_id) eina_hash_del(aliases[type], &alias_id, cp);
eina_hash_del(pixmaps[type], &id, cp);
#endif
break;
default: break;
}
return 0;
}
E_API E_Pixmap *
e_pixmap_ref(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
cp->refcount++;
return cp;
}
E_API E_Pixmap *
e_pixmap_new(E_Pixmap_Type type, ...)
{
E_Pixmap *cp = NULL;
va_list l;
#ifndef HAVE_WAYLAND_ONLY
Ecore_X_Window xwin;
#endif
#ifdef HAVE_WAYLAND
int64_t id;
#endif
EINA_SAFETY_ON_TRUE_RETURN_VAL((type != E_PIXMAP_TYPE_WL) &&
(type != E_PIXMAP_TYPE_X), NULL);
va_start(l, type);
switch (type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
xwin = va_arg(l, uint32_t);
if (pixmaps[type])
{
cp = eina_hash_find(pixmaps[type], &xwin);
if (cp)
{
cp->refcount++;
break;
}
}
else
pixmaps[type] = eina_hash_int32_new((Eina_Free_Cb)_e_pixmap_free);
cp = _e_pixmap_new(type);
cp->win = xwin;
eina_hash_add(pixmaps[type], &xwin, cp);
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
id = va_arg(l, int64_t);
if (pixmaps[type])
{
cp = eina_hash_find(pixmaps[type], &id);
if (cp)
{
cp->refcount++;
break;
}
}
else
{
pixmaps[type] = eina_hash_int64_new((Eina_Free_Cb)_e_pixmap_free);
}
cp = _e_pixmap_new(type);
cp->win = id;
eina_hash_add(pixmaps[type], &id, cp);
#endif
break;
default: break;
}
va_end(l);
return cp;
}
E_API E_Pixmap_Type
e_pixmap_type_get(const E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 9999);
return cp->type;
}
E_API void
e_pixmap_parent_window_set(E_Pixmap *cp, Ecore_Window win)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
if (cp->parent == win) return;
e_pixmap_usable_set(cp, 0);
e_pixmap_clear(cp);
cp->parent = win;
}
E_API void
e_pixmap_visual_cmap_set(E_Pixmap *cp, void *visual, unsigned int cmap)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
if (cp->type != E_PIXMAP_TYPE_X) return;
#ifndef HAVE_WAYLAND_ONLY
cp->visual = visual;
cp->cmap = cmap;
#else
(void) visual;
(void) cmap;
#endif
}
E_API void *
e_pixmap_visual_get(const E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
if (cp->type != E_PIXMAP_TYPE_X) return NULL;
#ifndef HAVE_WAYLAND_ONLY
return cp->visual;
#endif
return NULL;
}
E_API uint32_t
e_pixmap_pixmap_get(const E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
#ifndef HAVE_WAYLAND_ONLY
if (e_pixmap_is_x(cp)) return cp->pixmap;
#endif
return 0;
}
E_API void
e_pixmap_usable_set(E_Pixmap *cp, Eina_Bool set)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
cp->usable = !!set;
}
E_API Eina_Bool
e_pixmap_usable_get(const E_Pixmap *cp)
{
if (!cp) return EINA_FALSE;
// EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
return cp->usable;
}
E_API Eina_Bool
e_pixmap_dirty_get(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
return cp->dirty;
}
E_API void
e_pixmap_clear(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
_e_pixmap_clear(cp, 0);
cp->dirty = EINA_TRUE;
}
E_API void
e_pixmap_dirty(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
cp->dirty = 1;
}
E_API Eina_Bool
e_pixmap_refresh(E_Pixmap *cp)
{
Eina_Bool success = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
if (!cp->dirty) return EINA_TRUE;
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
{
uint32_t pixmap;
int pw, ph;
E_Comp_X_Client_Data *cd = NULL;
if (!cp->usable)
{
cp->failures++;
return EINA_FALSE;
}
pixmap =
ecore_x_composite_name_window_pixmap_get(cp->parent ?:
(Ecore_X_Window)cp->win);
if (cp->client)
{
cd = (E_Comp_X_Client_Data*)cp->client->comp_data;
}
success = !!pixmap;
if (!success) break;
if (cd && cd->pw && cd->ph)
{
pw = cd->pw;
ph = cd->ph;
}
else
ecore_x_pixmap_geometry_get(pixmap, NULL, NULL, &pw, &ph);
success = (pw > 0) && (ph > 0);
if (success)
{
if ((pw != cp->w) || (ph != cp->h))
{
ecore_x_pixmap_free(cp->pixmap);
cp->pixmap = pixmap;
cp->w = pw, cp->h = ph;
ecore_x_e_comp_pixmap_set(cp->parent ?:
(Ecore_X_Window)cp->win,
cp->pixmap);
e_pixmap_image_clear(cp, 0);
}
else
ecore_x_pixmap_free(pixmap);
}
else
ecore_x_pixmap_free(pixmap);
}
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
{
E_Comp_Wl_Buffer *buffer = cp->buffer;
int format;
cp->w = cp->h = 0;
cp->image_argb = EINA_FALSE;
if (!buffer) return EINA_FALSE;
cp->w = buffer->w;
cp->h = buffer->h;
if (buffer->shm_buffer)
format = wl_shm_buffer_get_format(buffer->shm_buffer);
else if (buffer->dmabuf_buffer)
format = buffer->dmabuf_buffer->attributes.format;
else if (e_comp_wl->wl.glapi)
{
e_comp_wl->wl.glapi->evasglQueryWaylandBuffer
(e_comp_wl->wl.gl, buffer->resource, EGL_TEXTURE_FORMAT,
&format);
}
else return EINA_FALSE;
switch (format)
{
case DRM_FORMAT_ARGB8888:
case WL_SHM_FORMAT_ARGB8888:
case EGL_TEXTURE_RGBA:
cp->image_argb = EINA_TRUE;
break;
default:
cp->image_argb = EINA_FALSE;
break;
}
success = ((cp->w > 0) && (cp->h > 0));
}
#endif
break;
default:
break;
}
if (success)
{
cp->dirty = 0;
cp->failures = 0;
}
else
cp->failures++;
return success;
}
E_API Eina_Bool
e_pixmap_size_changed(E_Pixmap *cp, int w, int h)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
if (cp->dirty) return EINA_TRUE;
return (w != cp->w) || (h != cp->h);
}
E_API Eina_Bool
e_pixmap_size_get(E_Pixmap *cp, int *w, int *h)
{
if (w) *w = 0;
if (h) *h = 0;
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
if (w) *w = cp->w;
if (h) *h = cp->h;
return (cp->w > 0) && (cp->h > 0);
}
E_API unsigned int
e_pixmap_failures_get(const E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
return cp->failures;
}
E_API void
e_pixmap_client_set(E_Pixmap *cp, E_Client *ec)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
if (cp->client && ec) CRI("ACK!");
cp->client = ec;
}
E_API E_Client *
e_pixmap_client_get(E_Pixmap *cp)
{
if (!cp) return NULL;
return cp->client;
}
E_API E_Pixmap *
e_pixmap_find(E_Pixmap_Type type, ...)
{
va_list l;
E_Pixmap *cp;
va_start(l, type);
cp = _e_pixmap_find(type, &l);
va_end(l);
return cp;
}
E_API E_Client *
e_pixmap_find_client(E_Pixmap_Type type, ...)
{
va_list l;
E_Pixmap *cp;
va_start(l, type);
cp = _e_pixmap_find(type, &l);
va_end(l);
return (!cp) ? NULL : cp->client;
}
E_API int64_t
e_pixmap_window_get(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
return cp->win;
}
E_API void *
e_pixmap_resource_get(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
if (cp->type != E_PIXMAP_TYPE_WL)
{
CRI("ACK");
return NULL;
}
#ifdef HAVE_WAYLAND
return cp->buffer;
#endif
return NULL;
}
E_API void
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)
{
if (resource)
{
if (cp->buffer->busy == 1)
{
// about to go to busy 0, so remove from list
cp->busy_list = eina_list_remove(cp->busy_list, cp->buffer);
}
_e_pixmap_wl_resource_release(cp->buffer);
}
}
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);
if (cp->buffer->dmabuf_buffer)
linux_dmabuf_buffer_ref(cp->buffer->dmabuf_buffer);
cp->buffer->busy++;
if (cp->buffer->busy > 0)
{
cp->busy_list = eina_list_remove(cp->busy_list, cp->buffer);
cp->busy_list = eina_list_append(cp->busy_list, cp->buffer);
}
#else
(void)resource;
#endif
}
E_API Ecore_Window
e_pixmap_parent_window_get(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
return cp->parent;
}
E_API Eina_Bool
e_pixmap_is_pixels(E_Pixmap *cp)
{
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
return EINA_FALSE;
#ifdef HAVE_WAYLAND
case E_PIXMAP_TYPE_WL:
if (!cp->buffer) return EINA_TRUE;
if (cp->buffer->shm_buffer) return EINA_TRUE;
return EINA_FALSE;
#endif
default:
return EINA_TRUE;
}
}
#ifdef HAVE_WAYLAND
static void
_e_pixmap_scanout_handler(void *data, Evas_Native_Surface_Status status)
{
E_Comp_Wl_Buffer *buffer = data;
printf("EWL: %s, Status: %d\n", __FUNCTION__, status);
switch (status)
{
case EVAS_NATIVE_SURFACE_STATUS_SCANOUT_ON:
if (buffer->dmabuf_buffer)
linux_dmabuf_buffer_ref(buffer->dmabuf_buffer);
buffer->busy++;
// XXX: fixme - handle cp->busy_list
break;
case EVAS_NATIVE_SURFACE_STATUS_SCANOUT_OFF:
// busy--
// XXX: fixme - handle cp->busy_list
_e_pixmap_wl_resource_release(buffer);
break;
case EVAS_NATIVE_SURFACE_STATUS_PLANE_ASSIGN:
if (buffer->dmabuf_buffer)
linux_dmabuf_buffer_ref(buffer->dmabuf_buffer);
// XXX: fixme - handle cp->busy_list
buffer->busy++;
break;
case EVAS_NATIVE_SURFACE_STATUS_PLANE_RELEASE:
// busy--
// XXX: fixme - handle cp->busy_list
_e_pixmap_wl_resource_release(buffer);
break;
}
}
#endif
E_API Eina_Bool
e_pixmap_native_surface_init(E_Pixmap *cp, Evas_Native_Surface *ns)
{
Eina_Bool ret = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(ns, EINA_FALSE);
/* This structure is stack automatic in the caller, so it's all
* uninitialized. Clear it to 0 so we don't have uninit data for
* variables only present in a newer version of native surface
* than this code was written for.
*
* The other option would be to set ns->version to whatever version
* this code was actually written against, but I've been told all
* native surface users are expected to set ns->version to the
* version provided in the headers (EVAS_NATIVE_SURFACE_VERSION)
*/
memset(ns, 0, sizeof(*ns));
ns->version = EVAS_NATIVE_SURFACE_VERSION;
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
ns->type = EVAS_NATIVE_SURFACE_X11;
ns->data.x11.visual = cp->visual;
ns->data.x11.pixmap = cp->pixmap;
ret = EINA_TRUE;
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
if (!cp->buffer) return EINA_FALSE;
if (cp->buffer->dmabuf_buffer)
{
static signed char use_hw_planes = -1;
ns->type = EVAS_NATIVE_SURFACE_WL_DMABUF;
ns->data.wl_dmabuf.attr = &cp->buffer->dmabuf_buffer->attributes;
ns->data.wl_dmabuf.resource = cp->buffer->resource;
if (use_hw_planes == -1)
{
if (getenv("E_USE_HARDWARE_PLANES")) use_hw_planes = 1;
else use_hw_planes = 0;
}
if (use_hw_planes)
{
ns->data.wl_dmabuf.scanout.handler =
_e_pixmap_scanout_handler;
ns->data.wl_dmabuf.scanout.data = cp->buffer;
}
ret = EINA_TRUE;
}
else if (!cp->buffer->shm_buffer)
{
ns->type = EVAS_NATIVE_SURFACE_WL;
ns->data.wl.legacy_buffer = cp->buffer->resource;
ret = EINA_TRUE;
}
else ret = EINA_FALSE;
#endif
break;
default:
break;
}
return ret;
}
E_API void
e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
if (!cache)
{
#ifndef HAVE_WAYLAND_ONLY
if (e_pixmap_is_x(cp))
if (!cp->image) return;
#endif
#ifdef HAVE_WAYLAND
if (cp->type == E_PIXMAP_TYPE_WL)
if (!cp->buffer) return;
#endif
}
cp->failures = 0;
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if (cache)
{
void *i;
EINA_LIST_FREE(cp->images_cache, i)
ecore_job_add((Ecore_Cb)ecore_x_image_free, i);
}
else
{
cp->images_cache = eina_list_append(cp->images_cache, cp->image);
cp->image = NULL;
}
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
_e_pixmap_wl_buffers_free(cp);
if (cache)
{
E_Comp_Wl_Client_Data *cd;
struct wl_resource *cb;
Eina_List *free_list;
double t;
if ((!cp->client) || (!cp->client->comp_data)) return;
cd = (E_Comp_Wl_Client_Data *)cp->client->comp_data;
/* The destroy callback will remove items from the frame list
* so we move the list to a temporary before walking it here
*/
free_list = cd->frames;
cd->frames = NULL;
t = ecore_loop_time_get();
EINA_LIST_FREE(free_list, cb)
{
// printf("E: frame request: %p [%ix%i] %1.5f @ %1.5f\n", cp, cp->w, cp->h, t, ecore_time_get());
wl_callback_send_done(cb, t * 1000);
wl_resource_destroy(cb);
}
}
#endif
break;
default:
break;
}
}
E_API Eina_Bool
e_pixmap_image_refresh(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
#ifndef HAVE_WAYLAND_ONLY
if (cp->image) return EINA_TRUE;
#endif
if (cp->dirty)
{
CRI("BUG! PIXMAP %p IS DIRTY!", cp);
return EINA_FALSE;
}
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if (cp->image) return EINA_TRUE;
if ((!cp->visual) || (!cp->client->depth)) return EINA_FALSE;
cp->image =
ecore_x_image_new(cp->w, cp->h, cp->visual, cp->client->depth);
if (cp->image)
cp->image_argb = ecore_x_image_is_argb32_get(cp->image);
return !!cp->image;
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
{
if (cp->held_buffer == cp->buffer) return EINA_TRUE;
if (cp->held_buffer) _e_pixmap_wayland_image_clear(cp);
/* This catches the case where a client (*cough* xwayland)
* deletes a buffer we haven't released
*/
if (!cp->buffer) return EINA_FALSE;
if (!cp->buffer->shm_buffer) return EINA_TRUE;
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;
if (cp->held_buffer_destroy_listener.link.next)
wl_list_remove(&cp->held_buffer_destroy_listener.link);
wl_signal_add(&cp->held_buffer->destroy_signal,
&cp->held_buffer_destroy_listener);
return EINA_TRUE;
}
#endif
break;
default:
break;
}
return EINA_FALSE;
}
E_API Eina_Bool
e_pixmap_image_exists(const E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
#ifndef HAVE_WAYLAND_ONLY
if (cp->type == E_PIXMAP_TYPE_X)
return !!cp->image;
#endif
#ifdef HAVE_WAYLAND
return (!!cp->data) ||
(cp->buffer && ((e_comp->gl && (!cp->buffer->shm_buffer)) ||
cp->buffer->dmabuf_buffer));
#endif
return EINA_FALSE;
}
E_API Eina_Bool
e_pixmap_image_is_argb(const E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
return cp->image && cp->image_argb;
#endif
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
if (cp->usable)
return cp->image_argb;
/* only cursors can be override in wayland */
if (cp->client->override) return EINA_TRUE;
#endif
default: break;
}
return EINA_FALSE;
}
E_API void *
e_pixmap_image_data_get(E_Pixmap *cp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if (cp->image)
return ecore_x_image_data_get(cp->image, &cp->ibpl, NULL, &cp->ibpp);
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
return cp->data;
#endif
break;
default:
break;
}
return NULL;
}
E_API Eina_Bool
e_pixmap_image_data_argb_convert(E_Pixmap *cp, void *pix, void *ipix, Eina_Rectangle *r, int stride)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
if (cp->image_argb) return EINA_TRUE;
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
if (cp->image_argb) return EINA_TRUE;
#ifndef HAVE_WAYLAND_ONLY
return ecore_x_image_to_argb_convert(ipix, cp->ibpp, cp->ibpl,
cp->cmap, cp->visual,
r->x, r->y, r->w, r->h,
pix, stride, r->x, r->y);
#endif
break;
case E_PIXMAP_TYPE_WL:
if (cp->image_argb) return EINA_TRUE;
return EINA_FALSE;
default:
break;
}
return EINA_FALSE;
}
E_API Eina_Bool
e_pixmap_image_draw(E_Pixmap *cp, const Eina_Rectangle *r)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
switch (cp->type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
if ((!cp->image) || (!cp->pixmap)) return EINA_FALSE;
return ecore_x_image_get(cp->image, cp->pixmap, r->x, r->y, r->x, r->y, r->w, r->h);
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
#endif
(void) r;
return EINA_TRUE;
default:
break;
}
return EINA_FALSE;
}
E_API void
e_pixmap_image_opaque_set(E_Pixmap *cp, int x, int y, int w, int h)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
#ifdef HAVE_WAYLAND
EINA_RECTANGLE_SET(&cp->opaque, x, y, w, h);
#else
(void)x;
(void)y;
(void)w;
(void)h;
#endif
}
E_API void
e_pixmap_image_opaque_get(E_Pixmap *cp, int *x, int *y, int *w, int *h)
{
EINA_SAFETY_ON_NULL_RETURN(cp);
#ifdef HAVE_WAYLAND
if (x) *x = cp->opaque.x;
if (y) *y = cp->opaque.y;
if (w) *w = cp->opaque.w;
if (h) *h = cp->opaque.h;
#else
if (x) *x = 0;
if (y) *y = 0;
if (w) *w = 0;
if (h) *h = 0;
#endif
}
E_API void
e_pixmap_alias(E_Pixmap *cp, E_Pixmap_Type type, ...)
{
E_Pixmap *cp2;
va_list l;
#ifndef HAVE_WAYLAND_ONLY
Ecore_X_Window xwin;
#endif
#ifdef HAVE_WAYLAND
int64_t id;
#endif
va_start(l, type);
switch (type)
{
case E_PIXMAP_TYPE_X:
#ifndef HAVE_WAYLAND_ONLY
xwin = va_arg(l, uint32_t);
if (!aliases[type])
aliases[type] = eina_hash_int32_new(NULL);
cp2 = eina_hash_find(aliases[type], &xwin);
if ((cp2) && (!cp)) cp2->alias = 0;
else if (cp) cp->alias = xwin;
eina_hash_set(aliases[type], &xwin, cp);
#endif
break;
case E_PIXMAP_TYPE_WL:
#ifdef HAVE_WAYLAND
id = va_arg(l, int64_t);
if (!aliases[type])
aliases[type] = eina_hash_int64_new(NULL);
cp2 = eina_hash_find(aliases[type], &id);
if ((cp2) && (!cp)) cp2->alias = 0;
else if (cp) cp->alias = id;
eina_hash_set(aliases[type], &id, cp);
#endif
break;
default: break;
}
va_end(l);
}
#ifdef HAVE_WAYLAND
E_API Eina_Bool
e_pixmap_dmabuf_test(struct linux_dmabuf_buffer *dmabuf)
{
Evas_Native_Surface ns;
Evas_Object *test;
Eina_Bool ret;
int size;
void *data;
memset(&ns, 0, sizeof(ns));
ns.type = EVAS_NATIVE_SURFACE_WL_DMABUF;
ns.version = EVAS_NATIVE_SURFACE_VERSION;
ns.data.wl_dmabuf.attr = &dmabuf->attributes;
ns.data.wl_dmabuf.resource = NULL;
test = evas_object_image_add(e_comp->evas);
evas_object_image_native_surface_set(test, &ns);
ret = evas_object_image_load_error_get(test) == EVAS_LOAD_ERROR_NONE;
evas_object_del(test);
if (e_comp->gl || !ret)
return ret;
/* This is only legit for ARGB8888 */
size = dmabuf->attributes.height * dmabuf->attributes.stride[0];
data = mmap(NULL, size, PROT_READ, MAP_SHARED, dmabuf->attributes.fd[0], 0);
if (data == MAP_FAILED) return EINA_FALSE;
munmap(data, size);
return EINA_TRUE;
}
/*
if (weston_check_egl_extension(extensions,
"EGL_EXT_image_dma_buf_import_modifiers")) {
gr->query_dmabuf_formats =
(void *) eglGetProcAddress("eglQueryDmaBufFormatsEXT");
gr->query_dmabuf_modifiers =
(void *) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
assert(gr->query_dmabuf_formats);
assert(gr->query_dmabuf_modifiers);
gr->has_dmabuf_import_modifiers = true;
}
*/
extern Eina_Bool e_comp_wl_query_dmabuf_formats(int max_formats, int *formats, int *num_formats);
extern Eina_Bool e_comp_wl_query_dmabuf_modifiers(int format, int max_modifiers, uint64_t *modifiers, Eina_Bool *external_only, int *num_modifiers);
E_API Eina_Bool
e_pixmap_dmabuf_formats_query(int **formats, int *num_formats)
{
static const int fallback_formats[] =
{
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
// support later ...
// DRM_FORMAT_YUYV,
// DRM_FORMAT_NV12,
// DRM_FORMAT_YUV420,
// DRM_FORMAT_YUV444,
// DRM_FORMAT_XYUV8888,
};
Eina_Bool fallback = EINA_FALSE;
int num = 0;
if (!e_comp_wl_query_dmabuf_formats(0, NULL, &num))
{
num = 2;
fallback = EINA_TRUE;
}
*formats = calloc(num, sizeof(int));
if (!(*formats))
{
*num_formats = 0;
return EINA_FALSE;
}
if (fallback)
{
memcpy(*formats, fallback_formats, num * sizeof(int));
*num_formats = num;
return EINA_TRUE;
}
if (!e_comp_wl_query_dmabuf_formats(num, *formats, &num))
{
*num_formats = 0;
free(*formats);
return EINA_FALSE;
}
*num_formats = num;
return EINA_TRUE;
}
E_API Eina_Bool
e_pixmap_dmabuf_modifiers_query(int format, uint64_t **modifiers, int *num_modifiers)
{
int num;
if (!e_comp_wl_query_dmabuf_modifiers(format, 0, NULL, NULL, &num) ||
(num == 0))
{
*num_modifiers = 0;
return EINA_FALSE;
}
*modifiers = calloc(num, sizeof(uint64_t));
if (!(*modifiers))
{
*num_modifiers = 0;
return EINA_FALSE;
}
if (!e_comp_wl_query_dmabuf_modifiers
(format, num, *modifiers, NULL, &num))
{
*num_modifiers = 0;
free(*modifiers);
return EINA_FALSE;
}
*num_modifiers = num;
return EINA_TRUE;
}
#endif