1 #include "e.h"
2 
3 #ifdef HAVE_WAYLAND
4 # include "e_comp_wl.h"
5 # ifndef EGL_TEXTURE_FORMAT
6 #  define EGL_TEXTURE_FORMAT		0x3080
7 # endif
8 # ifndef EGL_TEXTURE_RGBA
9 #  define EGL_TEXTURE_RGBA		0x305E
10 # endif
11 # ifndef DRM_FORMAT_ARGB8888
12 #  define DRM_FORMAT_ARGB8888           0x34325241
13 #  define DRM_FORMAT_XRGB8888           0x34325258
14 # endif
15 #endif
16 #ifndef HAVE_WAYLAND_ONLY
17 # include "e_comp_x.h"
18 #endif
19 
20 #include <sys/mman.h>
21 
22 static Eina_Hash *pixmaps[2] = {NULL};
23 static Eina_Hash *aliases[2] = {NULL};
24 
25 struct _E_Pixmap
26 {
27    unsigned int refcount;
28    unsigned int failures;
29 
30    E_Client *client;
31    E_Pixmap_Type type;
32 
33    int64_t win;
34    int64_t alias;
35    Ecore_Window parent;
36 
37    int w, h;
38 
39 #ifndef HAVE_WAYLAND_ONLY
40    void *image;
41    void *visual;
42    int ibpp, ibpl;
43    unsigned int cmap;
44    uint32_t pixmap;
45    Eina_List *images_cache;
46 #endif
47 
48 #ifdef HAVE_WAYLAND
49    E_Comp_Wl_Buffer *buffer;
50    E_Comp_Wl_Buffer *held_buffer;
51    struct wl_listener buffer_destroy_listener;
52    struct wl_listener held_buffer_destroy_listener;
53    void *data;
54    Eina_Rectangle opaque;
55    Eina_List *free_buffers;
56 #endif
57 
58    Eina_Bool usable E_BITFIELD;
59    Eina_Bool dirty E_BITFIELD;
60    Eina_Bool image_argb E_BITFIELD;
61 };
62 
63 #ifdef HAVE_WAYLAND
64 
65 double wayland_time_base;
66 
67 static void
_e_pixmap_cb_deferred_buffer_destroy(struct wl_listener * listener,void * data EINA_UNUSED)68 _e_pixmap_cb_deferred_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
69 {
70    E_Comp_Wl_Buffer *buffer;
71 
72    buffer = container_of(listener, E_Comp_Wl_Buffer, deferred_destroy_listener);
73    buffer->discarding_pixmap->free_buffers =
74      eina_list_remove(buffer->discarding_pixmap->free_buffers, buffer);
75    buffer->discarding_pixmap = NULL;
76 }
77 
78 static void
_e_pixmap_cb_buffer_destroy(struct wl_listener * listener,void * data EINA_UNUSED)79 _e_pixmap_cb_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
80 {
81    E_Pixmap *cp;
82 
83    cp = container_of(listener, E_Pixmap, buffer_destroy_listener);
84    cp->buffer = NULL;
85    cp->buffer_destroy_listener.notify = NULL;
86 }
87 
88 static void
_e_pixmap_cb_held_buffer_destroy(struct wl_listener * listener,void * data EINA_UNUSED)89 _e_pixmap_cb_held_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
90 {
91    E_Pixmap *cp;
92 
93    cp = container_of(listener, E_Pixmap, held_buffer_destroy_listener);
94    cp->held_buffer = NULL;
95    cp->held_buffer_destroy_listener.notify = NULL;
96 }
97 #endif
98 
99 static void
_e_pixmap_clear(E_Pixmap * cp,Eina_Bool cache)100 _e_pixmap_clear(E_Pixmap *cp, Eina_Bool cache)
101 {
102    cp->w = cp->h = 0;
103    cp->image_argb = EINA_FALSE;
104    switch (cp->type)
105      {
106       case E_PIXMAP_TYPE_X:
107 #ifndef HAVE_WAYLAND_ONLY
108         if (cp->pixmap)
109           {
110              ecore_x_pixmap_free(cp->pixmap);
111              cp->pixmap = 0;
112              ecore_x_e_comp_pixmap_set(cp->parent ?: (Ecore_X_Window)cp->win, 0);
113              e_pixmap_image_clear(cp, cache);
114           }
115 #endif
116         break;
117       case E_PIXMAP_TYPE_WL:
118 #ifdef HAVE_WAYLAND
119         e_pixmap_image_clear(cp, cache);
120 #endif
121         break;
122       default:
123         break;
124      }
125 }
126 
127 #ifndef HAVE_WAYLAND_ONLY
128 static void
_e_pixmap_image_clear_x(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)129 _e_pixmap_image_clear_x(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
130 {
131    Eina_List *list = data;
132    E_FREE_LIST(list, ecore_x_image_free);
133 }
134 #endif
135 
136 #ifdef HAVE_WAYLAND
137 static void
_e_pixmap_wl_resource_release(E_Comp_Wl_Buffer * buffer)138 _e_pixmap_wl_resource_release(E_Comp_Wl_Buffer *buffer)
139 {
140    buffer->busy--;
141    if (buffer->busy) return;
142 
143    if (buffer->pool)
144      {
145         wl_shm_pool_unref(buffer->pool);
146         buffer->pool = NULL;
147      }
148 
149    if (buffer->destroyed)
150      {
151         free(buffer);
152         return;
153      }
154 
155    wl_buffer_send_release(buffer->resource);
156 }
157 
158 static void
_e_pixmap_wayland_buffer_release(E_Pixmap * cp,E_Comp_Wl_Buffer * buffer)159 _e_pixmap_wayland_buffer_release(E_Pixmap *cp, E_Comp_Wl_Buffer *buffer)
160 {
161    if (!buffer) return;
162 
163    if (e_comp->rendering)
164      {
165         if (buffer->discarding_pixmap) return;
166 
167         buffer->discarding_pixmap = cp;
168         buffer->deferred_destroy_listener.notify =
169           _e_pixmap_cb_deferred_buffer_destroy;
170         wl_signal_add(&buffer->destroy_signal,
171                       &buffer->deferred_destroy_listener);
172         cp->free_buffers = eina_list_append(cp->free_buffers, buffer);
173         return;
174      }
175 
176    _e_pixmap_wl_resource_release(buffer);
177 }
178 
179 static void
_e_pixmap_wl_buffers_free(E_Pixmap * cp)180 _e_pixmap_wl_buffers_free(E_Pixmap *cp)
181 {
182    E_Comp_Wl_Buffer *b;
183 
184    EINA_LIST_FREE(cp->free_buffers, b)
185      {
186         wl_list_remove(&b->deferred_destroy_listener.link);
187         b->deferred_destroy_listener.notify = NULL;
188         _e_pixmap_wayland_buffer_release(cp, b);
189         b->discarding_pixmap = NULL;
190      }
191 }
192 
193 static void
_e_pixmap_wayland_image_clear(E_Pixmap * cp)194 _e_pixmap_wayland_image_clear(E_Pixmap *cp)
195 {
196    EINA_SAFETY_ON_NULL_RETURN(cp);
197 
198    if (!cp->held_buffer) return;
199    if (!cp->held_buffer->pool) return;
200 
201    _e_pixmap_wayland_buffer_release(cp, cp->held_buffer);
202    if (cp->held_buffer_destroy_listener.notify)
203      {
204         wl_list_remove(&cp->held_buffer_destroy_listener.link);
205         cp->held_buffer_destroy_listener.notify = NULL;
206      }
207 
208    cp->data = NULL;
209    cp->held_buffer = NULL;
210 }
211 #endif
212 
213 static void
_e_pixmap_free(E_Pixmap * cp)214 _e_pixmap_free(E_Pixmap *cp)
215 {
216    switch (cp->type)
217      {
218       case E_PIXMAP_TYPE_X:
219 #ifndef HAVE_WAYLAND_ONLY
220         if (!cp->images_cache) break;
221         if (cp->client)
222           evas_object_event_callback_add(cp->client->frame,
223                                          EVAS_CALLBACK_FREE,
224                                          _e_pixmap_image_clear_x,
225                                          cp->images_cache);
226         else
227           {
228              void *i;
229 
230              EINA_LIST_FREE(cp->images_cache, i)
231                ecore_job_add((Ecore_Cb)ecore_x_image_free, i);
232           }
233         cp->images_cache = NULL;
234 #endif
235         break;
236       case E_PIXMAP_TYPE_WL:
237 #ifdef HAVE_WAYLAND
238         _e_pixmap_wayland_image_clear(cp);
239         if (cp->buffer_destroy_listener.notify)
240           {
241              wl_list_remove(&cp->buffer_destroy_listener.link);
242              cp->buffer_destroy_listener.notify = NULL;
243           }
244 #endif
245         break;
246       default:
247         break;
248      }
249    _e_pixmap_clear(cp, 1);
250    free(cp);
251 }
252 
253 static E_Pixmap *
_e_pixmap_new(E_Pixmap_Type type)254 _e_pixmap_new(E_Pixmap_Type type)
255 {
256    E_Pixmap *cp;
257 
258    cp = E_NEW(E_Pixmap, 1);
259    cp->type = type;
260    cp->w = cp->h = 0;
261    cp->refcount = 1;
262    cp->dirty = 1;
263    return cp;
264 }
265 
266 static E_Pixmap *
_e_pixmap_find(E_Pixmap_Type type,va_list * l)267 _e_pixmap_find(E_Pixmap_Type type, va_list *l)
268 {
269 #ifndef HAVE_WAYLAND_ONLY
270    Ecore_X_Window xwin;
271 #endif
272 #ifdef HAVE_WAYLAND
273    int64_t id;
274 #endif
275    E_Pixmap *cp;
276 
277    if (!pixmaps[type]) return NULL;
278    switch (type)
279      {
280       case E_PIXMAP_TYPE_X:
281 #ifndef HAVE_WAYLAND_ONLY
282         xwin = va_arg(*l, uint32_t);
283         cp = eina_hash_find(aliases[type], &xwin);
284         if (!cp) cp = eina_hash_find(pixmaps[type], &xwin);
285         return cp;
286 #endif
287         break;
288       case E_PIXMAP_TYPE_WL:
289 #ifdef HAVE_WAYLAND
290         id = va_arg(*l, int64_t);
291         cp = eina_hash_find(aliases[type], &id);
292         if (!cp) cp = eina_hash_find(pixmaps[type], &id);
293         return cp;
294 #endif
295         break;
296       default: break;
297      }
298    return NULL;
299 }
300 
301 E_API int
e_pixmap_free(E_Pixmap * cp)302 e_pixmap_free(E_Pixmap *cp)
303 {
304 #ifndef HAVE_WAYLAND_ONLY
305    Ecore_X_Window xwin = cp ? cp->win : 0;
306    Ecore_X_Window alias_xwin = cp ? cp->alias : 0;
307 #endif
308 #ifdef HAVE_WAYLAND
309    int64_t id = cp ? cp->win : 0;
310    int64_t alias_id = cp ? cp->alias : 0;
311 #endif
312    E_Pixmap_Type type;
313 
314    if (!cp) return 0;
315    if (--cp->refcount) return cp->refcount;
316    type = cp->type;
317    e_pixmap_image_clear(cp, EINA_FALSE);
318    switch (type)
319      {
320       case E_PIXMAP_TYPE_X:
321 #ifndef HAVE_WAYLAND_ONLY
322         if (alias_xwin) eina_hash_del(aliases[type], &alias_xwin, cp);
323         eina_hash_del(pixmaps[type], &xwin, cp);
324 #endif
325         break;
326       case E_PIXMAP_TYPE_WL:
327 #ifdef HAVE_WAYLAND
328         if (alias_id) eina_hash_del(aliases[type], &alias_id, cp);
329         eina_hash_del(pixmaps[type], &id, cp);
330 #endif
331         break;
332       default: break;
333      }
334    return 0;
335 }
336 
337 E_API E_Pixmap *
e_pixmap_ref(E_Pixmap * cp)338 e_pixmap_ref(E_Pixmap *cp)
339 {
340    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
341    cp->refcount++;
342    return cp;
343 }
344 
345 E_API E_Pixmap *
e_pixmap_new(E_Pixmap_Type type,...)346 e_pixmap_new(E_Pixmap_Type type, ...)
347 {
348    E_Pixmap *cp = NULL;
349    va_list l;
350 #ifndef HAVE_WAYLAND_ONLY
351    Ecore_X_Window xwin;
352 #endif
353 #ifdef HAVE_WAYLAND
354    int64_t id;
355 #endif
356 
357    EINA_SAFETY_ON_TRUE_RETURN_VAL((type != E_PIXMAP_TYPE_WL) &&
358                                   (type != E_PIXMAP_TYPE_X), NULL);
359    va_start(l, type);
360    switch (type)
361      {
362       case E_PIXMAP_TYPE_X:
363 #ifndef HAVE_WAYLAND_ONLY
364         xwin = va_arg(l, uint32_t);
365         if (pixmaps[type])
366           {
367              cp = eina_hash_find(pixmaps[type], &xwin);
368              if (cp)
369                {
370                   cp->refcount++;
371                   break;
372                }
373           }
374         else
375           pixmaps[type] = eina_hash_int32_new((Eina_Free_Cb)_e_pixmap_free);
376         cp = _e_pixmap_new(type);
377         cp->win = xwin;
378         eina_hash_add(pixmaps[type], &xwin, cp);
379 #endif
380         break;
381       case E_PIXMAP_TYPE_WL:
382 #ifdef HAVE_WAYLAND
383         id = va_arg(l, int64_t);
384         if (pixmaps[type])
385           {
386              cp = eina_hash_find(pixmaps[type], &id);
387              if (cp)
388                {
389                   cp->refcount++;
390                   break;
391                }
392           }
393         else
394           {
395              pixmaps[type] = eina_hash_int64_new((Eina_Free_Cb)_e_pixmap_free);
396              wayland_time_base = ecore_loop_time_get();
397           }
398         cp = _e_pixmap_new(type);
399         cp->win = id;
400         eina_hash_add(pixmaps[type], &id, cp);
401 #endif
402         break;
403       default: break;
404      }
405    va_end(l);
406    return cp;
407 }
408 
409 E_API E_Pixmap_Type
e_pixmap_type_get(const E_Pixmap * cp)410 e_pixmap_type_get(const E_Pixmap *cp)
411 {
412    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 9999);
413    return cp->type;
414 }
415 
416 E_API void
e_pixmap_parent_window_set(E_Pixmap * cp,Ecore_Window win)417 e_pixmap_parent_window_set(E_Pixmap *cp, Ecore_Window win)
418 {
419    EINA_SAFETY_ON_NULL_RETURN(cp);
420    if (cp->parent == win) return;
421 
422    e_pixmap_usable_set(cp, 0);
423    e_pixmap_clear(cp);
424 
425    cp->parent = win;
426 }
427 
428 E_API void
e_pixmap_visual_cmap_set(E_Pixmap * cp,void * visual,unsigned int cmap)429 e_pixmap_visual_cmap_set(E_Pixmap *cp, void *visual, unsigned int cmap)
430 {
431    EINA_SAFETY_ON_NULL_RETURN(cp);
432    if (cp->type != E_PIXMAP_TYPE_X) return;
433 #ifndef HAVE_WAYLAND_ONLY
434    cp->visual = visual;
435    cp->cmap = cmap;
436 #else
437    (void) visual;
438    (void) cmap;
439 #endif
440 }
441 
442 E_API void *
e_pixmap_visual_get(const E_Pixmap * cp)443 e_pixmap_visual_get(const E_Pixmap *cp)
444 {
445    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
446    if (cp->type != E_PIXMAP_TYPE_X) return NULL;
447 #ifndef HAVE_WAYLAND_ONLY
448    return cp->visual;
449 #endif
450    return NULL;
451 }
452 
453 E_API uint32_t
e_pixmap_pixmap_get(const E_Pixmap * cp)454 e_pixmap_pixmap_get(const E_Pixmap *cp)
455 {
456    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
457 #ifndef HAVE_WAYLAND_ONLY
458    if (e_pixmap_is_x(cp)) return cp->pixmap;
459 #endif
460    return 0;
461 }
462 
463 E_API void
e_pixmap_usable_set(E_Pixmap * cp,Eina_Bool set)464 e_pixmap_usable_set(E_Pixmap *cp, Eina_Bool set)
465 {
466    EINA_SAFETY_ON_NULL_RETURN(cp);
467    cp->usable = !!set;
468 }
469 
470 E_API Eina_Bool
e_pixmap_usable_get(const E_Pixmap * cp)471 e_pixmap_usable_get(const E_Pixmap *cp)
472 {
473    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
474    return cp->usable;
475 }
476 
477 E_API Eina_Bool
e_pixmap_dirty_get(E_Pixmap * cp)478 e_pixmap_dirty_get(E_Pixmap *cp)
479 {
480    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
481    return cp->dirty;
482 }
483 
484 E_API void
e_pixmap_clear(E_Pixmap * cp)485 e_pixmap_clear(E_Pixmap *cp)
486 {
487    EINA_SAFETY_ON_NULL_RETURN(cp);
488    _e_pixmap_clear(cp, 0);
489    cp->dirty = EINA_TRUE;
490 }
491 
492 E_API void
e_pixmap_dirty(E_Pixmap * cp)493 e_pixmap_dirty(E_Pixmap *cp)
494 {
495    EINA_SAFETY_ON_NULL_RETURN(cp);
496    cp->dirty = 1;
497 }
498 
499 E_API Eina_Bool
e_pixmap_refresh(E_Pixmap * cp)500 e_pixmap_refresh(E_Pixmap *cp)
501 {
502    Eina_Bool success = EINA_FALSE;
503 
504    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
505 
506    if (!cp->dirty) return EINA_TRUE;
507    switch (cp->type)
508      {
509       case E_PIXMAP_TYPE_X:
510 #ifndef HAVE_WAYLAND_ONLY
511         {
512            uint32_t pixmap;
513            int pw, ph;
514            E_Comp_X_Client_Data *cd = NULL;
515 
516            if (!cp->usable)
517              {
518                 cp->failures++;
519                 return EINA_FALSE;
520              }
521            pixmap =
522              ecore_x_composite_name_window_pixmap_get(cp->parent ?:
523                                                       (Ecore_X_Window)cp->win);
524            if (cp->client)
525              {
526                 cd = (E_Comp_X_Client_Data*)cp->client->comp_data;
527              }
528            success = !!pixmap;
529            if (!success) break;
530            if (cd && cd->pw && cd->ph)
531              {
532                 pw = cd->pw;
533                 ph = cd->ph;
534              }
535            else
536              ecore_x_pixmap_geometry_get(pixmap, NULL, NULL, &pw, &ph);
537            success = (pw > 0) && (ph > 0);
538            if (success)
539              {
540                 if ((pw != cp->w) || (ph != cp->h))
541                   {
542                      ecore_x_pixmap_free(cp->pixmap);
543                      cp->pixmap = pixmap;
544                      cp->w = pw, cp->h = ph;
545                      ecore_x_e_comp_pixmap_set(cp->parent ?:
546                                                (Ecore_X_Window)cp->win,
547                                                cp->pixmap);
548                      e_pixmap_image_clear(cp, 0);
549                   }
550                 else
551                   ecore_x_pixmap_free(pixmap);
552              }
553            else
554              ecore_x_pixmap_free(pixmap);
555         }
556 #endif
557         break;
558       case E_PIXMAP_TYPE_WL:
559 #ifdef HAVE_WAYLAND
560         {
561            E_Comp_Wl_Buffer *buffer = cp->buffer;
562            int format;
563 
564            cp->w = cp->h = 0;
565            cp->image_argb = EINA_FALSE;
566 
567            if (!buffer) return EINA_FALSE;
568 
569            cp->w = buffer->w;
570            cp->h = buffer->h;
571 
572            if (buffer->shm_buffer)
573              format = wl_shm_buffer_get_format(buffer->shm_buffer);
574            else if (buffer->dmabuf_buffer)
575              format = buffer->dmabuf_buffer->attributes.format;
576            else
577              {
578                 e_comp_wl->wl.glapi->evasglQueryWaylandBuffer
579                   (e_comp_wl->wl.gl, buffer->resource, EGL_TEXTURE_FORMAT,
580                       &format);
581              }
582 
583            switch (format)
584              {
585               case DRM_FORMAT_ARGB8888:
586               case WL_SHM_FORMAT_ARGB8888:
587               case EGL_TEXTURE_RGBA:
588                 cp->image_argb = EINA_TRUE;
589                 break;
590               default:
591                 cp->image_argb = EINA_FALSE;
592                 break;
593              }
594 
595            success = ((cp->w > 0) && (cp->h > 0));
596         }
597 #endif
598         break;
599       default:
600         break;
601      }
602 
603    if (success)
604      {
605         cp->dirty = 0;
606         cp->failures = 0;
607      }
608    else
609      cp->failures++;
610    return success;
611 }
612 
613 E_API Eina_Bool
e_pixmap_size_changed(E_Pixmap * cp,int w,int h)614 e_pixmap_size_changed(E_Pixmap *cp, int w, int h)
615 {
616    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
617    if (cp->dirty) return EINA_TRUE;
618    return (w != cp->w) || (h != cp->h);
619 }
620 
621 E_API Eina_Bool
e_pixmap_size_get(E_Pixmap * cp,int * w,int * h)622 e_pixmap_size_get(E_Pixmap *cp, int *w, int *h)
623 {
624    if (w) *w = 0;
625    if (h) *h = 0;
626    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
627    if (w) *w = cp->w;
628    if (h) *h = cp->h;
629    return (cp->w > 0) && (cp->h > 0);
630 }
631 
632 E_API unsigned int
e_pixmap_failures_get(const E_Pixmap * cp)633 e_pixmap_failures_get(const E_Pixmap *cp)
634 {
635    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
636    return cp->failures;
637 }
638 
639 E_API void
e_pixmap_client_set(E_Pixmap * cp,E_Client * ec)640 e_pixmap_client_set(E_Pixmap *cp, E_Client *ec)
641 {
642    EINA_SAFETY_ON_NULL_RETURN(cp);
643    if (cp->client && ec) CRI("ACK!");
644    cp->client = ec;
645 }
646 
647 E_API E_Client *
e_pixmap_client_get(E_Pixmap * cp)648 e_pixmap_client_get(E_Pixmap *cp)
649 {
650    if (!cp) return NULL;
651    return cp->client;
652 }
653 
654 E_API E_Pixmap *
e_pixmap_find(E_Pixmap_Type type,...)655 e_pixmap_find(E_Pixmap_Type type, ...)
656 {
657    va_list l;
658    E_Pixmap *cp;
659 
660    va_start(l, type);
661    cp = _e_pixmap_find(type, &l);
662    va_end(l);
663    return cp;
664 }
665 
666 E_API E_Client *
e_pixmap_find_client(E_Pixmap_Type type,...)667 e_pixmap_find_client(E_Pixmap_Type type, ...)
668 {
669    va_list l;
670    E_Pixmap *cp;
671 
672    va_start(l, type);
673    cp = _e_pixmap_find(type, &l);
674    va_end(l);
675    return (!cp) ? NULL : cp->client;
676 }
677 
678 E_API int64_t
e_pixmap_window_get(E_Pixmap * cp)679 e_pixmap_window_get(E_Pixmap *cp)
680 {
681    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
682    return cp->win;
683 }
684 
685 E_API void *
e_pixmap_resource_get(E_Pixmap * cp)686 e_pixmap_resource_get(E_Pixmap *cp)
687 {
688    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
689    if (cp->type != E_PIXMAP_TYPE_WL)
690      {
691         CRI("ACK");
692         return NULL;
693      }
694 #ifdef HAVE_WAYLAND
695    return cp->buffer;
696 #endif
697    return NULL;
698 }
699 
700 E_API void
e_pixmap_resource_set(E_Pixmap * cp,void * resource)701 e_pixmap_resource_set(E_Pixmap *cp, void *resource)
702 {
703    if ((!cp) || (cp->type != E_PIXMAP_TYPE_WL)) return;
704 #ifdef HAVE_WAYLAND
705    if (cp->buffer == resource) return;
706 
707    if (cp->buffer)
708      _e_pixmap_wl_resource_release(cp->buffer);
709 
710    if (cp->buffer_destroy_listener.notify)
711      {
712         wl_list_remove(&cp->buffer_destroy_listener.link);
713         cp->buffer_destroy_listener.notify = NULL;
714      }
715    cp->buffer = resource;
716    if (!cp->buffer) return;
717    cp->buffer_destroy_listener.notify = _e_pixmap_cb_buffer_destroy;
718    wl_signal_add(&cp->buffer->destroy_signal,
719                  &cp->buffer_destroy_listener);
720 
721    cp->buffer->busy++;
722 #else
723    (void)resource;
724 #endif
725 }
726 
727 E_API Ecore_Window
e_pixmap_parent_window_get(E_Pixmap * cp)728 e_pixmap_parent_window_get(E_Pixmap *cp)
729 {
730    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, 0);
731    return cp->parent;
732 }
733 
734 E_API Eina_Bool
e_pixmap_is_pixels(E_Pixmap * cp)735 e_pixmap_is_pixels(E_Pixmap *cp)
736 {
737    switch (cp->type)
738      {
739         case E_PIXMAP_TYPE_X:
740           return EINA_FALSE;
741 #ifdef HAVE_WAYLAND
742         case E_PIXMAP_TYPE_WL:
743           if (!cp->buffer) return EINA_TRUE;
744           if (cp->buffer->shm_buffer) return EINA_TRUE;
745           return EINA_FALSE;
746 #endif
747         default:
748           return EINA_TRUE;
749      }
750 }
751 
752 #ifdef HAVE_WAYLAND
753 static void
_e_pixmap_scanout_handler(void * data,Evas_Native_Surface_Status status)754 _e_pixmap_scanout_handler(void *data, Evas_Native_Surface_Status status)
755 {
756    E_Comp_Wl_Buffer *buffer;
757 
758    printf("EWL: %s, Status: %d\n", __FUNCTION__, status);
759 
760    buffer = data;
761    switch (status)
762      {
763       case EVAS_NATIVE_SURFACE_STATUS_SCANOUT_ON:
764         buffer->busy++;
765         break;
766       case EVAS_NATIVE_SURFACE_STATUS_SCANOUT_OFF:
767         _e_pixmap_wl_resource_release(buffer);
768         break;
769       case EVAS_NATIVE_SURFACE_STATUS_PLANE_ASSIGN:
770         buffer->busy++;
771         break;
772       case EVAS_NATIVE_SURFACE_STATUS_PLANE_RELEASE:
773         _e_pixmap_wl_resource_release(buffer);
774         break;
775      }
776 }
777 #endif
778 
779 E_API Eina_Bool
e_pixmap_native_surface_init(E_Pixmap * cp,Evas_Native_Surface * ns)780 e_pixmap_native_surface_init(E_Pixmap *cp, Evas_Native_Surface *ns)
781 {
782    Eina_Bool ret = EINA_FALSE;
783 
784    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
785    EINA_SAFETY_ON_NULL_RETURN_VAL(ns, EINA_FALSE);
786 
787    /* This structure is stack automatic in the caller, so it's all
788     * uninitialized. Clear it to 0 so we don't have uninit data for
789     * variables only present in a newer version of native surface
790     * than this code was written for.
791     *
792     * The other option would be to set ns->version to whatever version
793     * this code was actually written against, but I've been told all
794     * native surface users are expected to set ns->version to the
795     * version provided in the headers (EVAS_NATIVE_SURFACE_VERSION)
796     */
797    memset(ns, 0, sizeof(*ns));
798    ns->version = EVAS_NATIVE_SURFACE_VERSION;
799    switch (cp->type)
800      {
801       case E_PIXMAP_TYPE_X:
802 #ifndef HAVE_WAYLAND_ONLY
803         ns->type = EVAS_NATIVE_SURFACE_X11;
804         ns->data.x11.visual = cp->visual;
805         ns->data.x11.pixmap = cp->pixmap;
806         ret = EINA_TRUE;
807 #endif
808         break;
809       case E_PIXMAP_TYPE_WL:
810 #ifdef HAVE_WAYLAND
811         if (!cp->buffer) return EINA_FALSE;
812         if (cp->buffer->dmabuf_buffer)
813           {
814              static signed char use_hw_planes = -1;
815              ns->type = EVAS_NATIVE_SURFACE_WL_DMABUF;
816 
817              ns->data.wl_dmabuf.attr = &cp->buffer->dmabuf_buffer->attributes;
818              ns->data.wl_dmabuf.resource = cp->buffer->resource;
819              if (use_hw_planes == -1)
820                {
821                   if (getenv("E_USE_HARDWARE_PLANES")) use_hw_planes = 1;
822                   else use_hw_planes = 0;
823                }
824              if (use_hw_planes)
825                {
826                   ns->data.wl_dmabuf.scanout.handler =
827                     _e_pixmap_scanout_handler;
828                   ns->data.wl_dmabuf.scanout.data = cp->buffer;
829                }
830              ret = EINA_TRUE;
831           }
832         else if (!cp->buffer->shm_buffer)
833           {
834              ns->type = EVAS_NATIVE_SURFACE_WL;
835              ns->data.wl.legacy_buffer = cp->buffer->resource;
836              ret = EINA_TRUE;
837           }
838         else ret = EINA_FALSE;
839 #endif
840         break;
841       default:
842         break;
843      }
844 
845    return ret;
846 }
847 
848 E_API void
e_pixmap_image_clear(E_Pixmap * cp,Eina_Bool cache)849 e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache)
850 {
851    EINA_SAFETY_ON_NULL_RETURN(cp);
852 
853    if (!cache)
854      {
855 #ifndef HAVE_WAYLAND_ONLY
856         if (e_pixmap_is_x(cp))
857           if (!cp->image) return;
858 #endif
859 #ifdef HAVE_WAYLAND
860         if (cp->type == E_PIXMAP_TYPE_WL)
861           if (!cp->buffer) return;
862 #endif
863      }
864 
865    cp->failures = 0;
866    switch (cp->type)
867      {
868       case E_PIXMAP_TYPE_X:
869 #ifndef HAVE_WAYLAND_ONLY
870         if (cache)
871           {
872              void *i;
873 
874              EINA_LIST_FREE(cp->images_cache, i)
875                ecore_job_add((Ecore_Cb)ecore_x_image_free, i);
876           }
877         else
878           {
879              cp->images_cache = eina_list_append(cp->images_cache, cp->image);
880              cp->image = NULL;
881           }
882 #endif
883         break;
884       case E_PIXMAP_TYPE_WL:
885 #ifdef HAVE_WAYLAND
886         _e_pixmap_wl_buffers_free(cp);
887         if (cache)
888           {
889              E_Comp_Wl_Client_Data *cd;
890              struct wl_resource *cb;
891              Eina_List *free_list;
892 
893              if ((!cp->client) || (!cp->client->comp_data)) return;
894 
895              cd = (E_Comp_Wl_Client_Data *)cp->client->comp_data;
896 
897              /* The destroy callback will remove items from the frame list
898               * so we move the list to a temporary before walking it here
899               */
900              free_list = cd->frames;
901              cd->frames = NULL;
902              EINA_LIST_FREE(free_list, cb)
903                {
904                   double t = ecore_loop_time_get();
905                   wl_callback_send_done(cb, t * 1000);
906                   wl_resource_destroy(cb);
907                }
908           }
909 #endif
910         break;
911       default:
912         break;
913      }
914 }
915 
916 E_API Eina_Bool
e_pixmap_image_refresh(E_Pixmap * cp)917 e_pixmap_image_refresh(E_Pixmap *cp)
918 {
919    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
920 
921 #ifndef HAVE_WAYLAND_ONLY
922    if (cp->image) return EINA_TRUE;
923 #endif
924 
925    if (cp->dirty)
926      {
927         CRI("BUG! PIXMAP %p IS DIRTY!", cp);
928         return EINA_FALSE;
929      }
930 
931    switch (cp->type)
932      {
933       case E_PIXMAP_TYPE_X:
934 #ifndef HAVE_WAYLAND_ONLY
935         if (cp->image) return EINA_TRUE;
936         if ((!cp->visual) || (!cp->client->depth)) return EINA_FALSE;
937         cp->image =
938           ecore_x_image_new(cp->w, cp->h, cp->visual, cp->client->depth);
939         if (cp->image)
940           cp->image_argb = ecore_x_image_is_argb32_get(cp->image);
941         return !!cp->image;
942 #endif
943         break;
944       case E_PIXMAP_TYPE_WL:
945 #ifdef HAVE_WAYLAND
946         {
947            if (cp->held_buffer == cp->buffer) return EINA_TRUE;
948 
949            if (cp->held_buffer) _e_pixmap_wayland_image_clear(cp);
950 
951            /* This catches the case where a client (*cough* xwayland)
952             * deletes a buffer we haven't released
953             */
954            if (!cp->buffer) return EINA_FALSE;
955 
956            if (!cp->buffer->shm_buffer) return EINA_TRUE;
957 
958            cp->held_buffer = cp->buffer;
959            if (!cp->held_buffer) return EINA_TRUE;
960 
961            cp->held_buffer->pool =
962              wl_shm_buffer_ref_pool(cp->held_buffer->shm_buffer);
963            cp->held_buffer->busy++;
964            cp->data = wl_shm_buffer_get_data(cp->buffer->shm_buffer);
965            cp->held_buffer_destroy_listener.notify =
966              _e_pixmap_cb_held_buffer_destroy;
967 
968            wl_signal_add(&cp->held_buffer->destroy_signal,
969                          &cp->held_buffer_destroy_listener);
970            return EINA_TRUE;
971         }
972 #endif
973         break;
974       default:
975         break;
976      }
977 
978    return EINA_FALSE;
979 }
980 
981 E_API Eina_Bool
e_pixmap_image_exists(const E_Pixmap * cp)982 e_pixmap_image_exists(const E_Pixmap *cp)
983 {
984    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
985 
986 #ifndef HAVE_WAYLAND_ONLY
987    if (cp->type == E_PIXMAP_TYPE_X)
988      return !!cp->image;
989 #endif
990 #ifdef HAVE_WAYLAND
991    return (!!cp->data) ||
992      (cp->buffer && ((e_comp->gl && (!cp->buffer->shm_buffer)) ||
993                      cp->buffer->dmabuf_buffer));
994 #endif
995 
996    return EINA_FALSE;
997 }
998 
999 E_API Eina_Bool
e_pixmap_image_is_argb(const E_Pixmap * cp)1000 e_pixmap_image_is_argb(const E_Pixmap *cp)
1001 {
1002    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
1003 
1004    switch (cp->type)
1005      {
1006       case E_PIXMAP_TYPE_X:
1007 #ifndef HAVE_WAYLAND_ONLY
1008         return cp->image && cp->image_argb;
1009 #endif
1010       case E_PIXMAP_TYPE_WL:
1011 #ifdef HAVE_WAYLAND
1012         if (cp->usable)
1013           return cp->image_argb;
1014         /* only cursors can be override in wayland */
1015         if (cp->client->override) return EINA_TRUE;
1016 #endif
1017         default: break;
1018      }
1019    return EINA_FALSE;
1020 }
1021 
1022 E_API void *
e_pixmap_image_data_get(E_Pixmap * cp)1023 e_pixmap_image_data_get(E_Pixmap *cp)
1024 {
1025    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);
1026 
1027    switch (cp->type)
1028      {
1029       case E_PIXMAP_TYPE_X:
1030 #ifndef HAVE_WAYLAND_ONLY
1031         if (cp->image)
1032           return ecore_x_image_data_get(cp->image, &cp->ibpl, NULL, &cp->ibpp);
1033 #endif
1034         break;
1035       case E_PIXMAP_TYPE_WL:
1036 #ifdef HAVE_WAYLAND
1037         return cp->data;
1038 #endif
1039         break;
1040       default:
1041         break;
1042      }
1043    return NULL;
1044 }
1045 
1046 E_API Eina_Bool
e_pixmap_image_data_argb_convert(E_Pixmap * cp,void * pix,void * ipix,Eina_Rectangle * r,int stride)1047 e_pixmap_image_data_argb_convert(E_Pixmap *cp, void *pix, void *ipix, Eina_Rectangle *r, int stride)
1048 {
1049    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
1050 
1051    if (cp->image_argb) return EINA_TRUE;
1052 
1053    switch (cp->type)
1054      {
1055       case E_PIXMAP_TYPE_X:
1056         if (cp->image_argb) return EINA_TRUE;
1057 #ifndef HAVE_WAYLAND_ONLY
1058         return ecore_x_image_to_argb_convert(ipix, cp->ibpp, cp->ibpl,
1059                                              cp->cmap, cp->visual,
1060                                              r->x, r->y, r->w, r->h,
1061                                              pix, stride, r->x, r->y);
1062 #endif
1063         break;
1064       case E_PIXMAP_TYPE_WL:
1065         if (cp->image_argb) return EINA_TRUE;
1066         return EINA_FALSE;
1067       default:
1068         break;
1069      }
1070    return EINA_FALSE;
1071 }
1072 
1073 E_API Eina_Bool
e_pixmap_image_draw(E_Pixmap * cp,const Eina_Rectangle * r)1074 e_pixmap_image_draw(E_Pixmap *cp, const Eina_Rectangle *r)
1075 {
1076    EINA_SAFETY_ON_NULL_RETURN_VAL(cp, EINA_FALSE);
1077 
1078    switch (cp->type)
1079      {
1080       case E_PIXMAP_TYPE_X:
1081 #ifndef HAVE_WAYLAND_ONLY
1082         if ((!cp->image) || (!cp->pixmap)) return EINA_FALSE;
1083         return ecore_x_image_get(cp->image, cp->pixmap, r->x, r->y, r->x, r->y, r->w, r->h);
1084 #endif
1085         break;
1086       case E_PIXMAP_TYPE_WL:
1087 #ifdef HAVE_WAYLAND
1088 #endif
1089         (void) r;
1090         return EINA_TRUE;
1091       default:
1092         break;
1093      }
1094    return EINA_FALSE;
1095 }
1096 
1097 E_API void
e_pixmap_image_opaque_set(E_Pixmap * cp,int x,int y,int w,int h)1098 e_pixmap_image_opaque_set(E_Pixmap *cp, int x, int y, int w, int h)
1099 {
1100    EINA_SAFETY_ON_NULL_RETURN(cp);
1101 #ifdef HAVE_WAYLAND
1102    EINA_RECTANGLE_SET(&cp->opaque, x, y, w, h);
1103 #else
1104    (void)x;
1105    (void)y;
1106    (void)w;
1107    (void)h;
1108 #endif
1109 }
1110 
1111 E_API void
e_pixmap_image_opaque_get(E_Pixmap * cp,int * x,int * y,int * w,int * h)1112 e_pixmap_image_opaque_get(E_Pixmap *cp, int *x, int *y, int *w, int *h)
1113 {
1114    EINA_SAFETY_ON_NULL_RETURN(cp);
1115 #ifdef HAVE_WAYLAND
1116    if (x) *x = cp->opaque.x;
1117    if (y) *y = cp->opaque.y;
1118    if (w) *w = cp->opaque.w;
1119    if (h) *h = cp->opaque.h;
1120 #else
1121    if (x) *x = 0;
1122    if (y) *y = 0;
1123    if (w) *w = 0;
1124    if (h) *h = 0;
1125 #endif
1126 }
1127 
1128 E_API void
e_pixmap_alias(E_Pixmap * cp,E_Pixmap_Type type,...)1129 e_pixmap_alias(E_Pixmap *cp, E_Pixmap_Type type, ...)
1130 {
1131    E_Pixmap *cp2;
1132    va_list l;
1133 #ifndef HAVE_WAYLAND_ONLY
1134    Ecore_X_Window xwin;
1135 #endif
1136 #ifdef HAVE_WAYLAND
1137    int64_t id;
1138 #endif
1139 
1140    va_start(l, type);
1141    switch (type)
1142      {
1143       case E_PIXMAP_TYPE_X:
1144 #ifndef HAVE_WAYLAND_ONLY
1145         xwin = va_arg(l, uint32_t);
1146         if (!aliases[type])
1147           aliases[type] = eina_hash_int32_new(NULL);
1148         cp2 = eina_hash_find(aliases[type], &xwin);
1149         if ((cp2) && (!cp)) cp2->alias = 0;
1150         else if (cp) cp->alias = xwin;
1151         eina_hash_set(aliases[type], &xwin, cp);
1152 #endif
1153         break;
1154       case E_PIXMAP_TYPE_WL:
1155 #ifdef HAVE_WAYLAND
1156         id = va_arg(l, int64_t);
1157         if (!aliases[type])
1158           aliases[type] = eina_hash_int64_new(NULL);
1159         cp2 = eina_hash_find(aliases[type], &id);
1160         if ((cp2) && (!cp)) cp2->alias = 0;
1161         else if (cp) cp->alias = id;
1162         eina_hash_set(aliases[type], &id, cp);
1163 #endif
1164         break;
1165       default: break;
1166      }
1167    va_end(l);
1168 }
1169 
1170 #ifdef HAVE_WAYLAND
1171 E_API Eina_Bool
e_pixmap_dmabuf_test(struct linux_dmabuf_buffer * dmabuf)1172 e_pixmap_dmabuf_test(struct linux_dmabuf_buffer *dmabuf)
1173 {
1174    Evas_Native_Surface ns;
1175    Evas_Object *test;
1176    Eina_Bool ret;
1177    int size;
1178    void *data;
1179 
1180    memset(&ns, 0, sizeof(ns));
1181 
1182    ns.type = EVAS_NATIVE_SURFACE_WL_DMABUF;
1183    ns.version = EVAS_NATIVE_SURFACE_VERSION;
1184    ns.data.wl_dmabuf.attr = &dmabuf->attributes;
1185    ns.data.wl_dmabuf.resource = NULL;
1186    test = evas_object_image_add(e_comp->evas);
1187    evas_object_image_native_surface_set(test, &ns);
1188    ret = evas_object_image_load_error_get(test) == EVAS_LOAD_ERROR_NONE;
1189    evas_object_del(test);
1190 
1191    if (e_comp->gl || !ret)
1192       return ret;
1193 
1194    /* This is only legit for ARGB8888 */
1195    size = dmabuf->attributes.height * dmabuf->attributes.stride[0];
1196    data = mmap(NULL, size, PROT_READ, MAP_SHARED, dmabuf->attributes.fd[0], 0);
1197    if (data == MAP_FAILED) return EINA_FALSE;
1198    munmap(data, size);
1199 
1200    return EINA_TRUE;
1201 }
1202 
1203 E_API Eina_Bool
e_pixmap_dmabuf_formats_query(int ** formats EINA_UNUSED,int * num_formats)1204 e_pixmap_dmabuf_formats_query(int **formats EINA_UNUSED, int *num_formats)
1205 {
1206    *num_formats = 0;
1207 
1208    return EINA_TRUE;
1209 }
1210 
1211 E_API Eina_Bool
e_pixmap_dmabuf_modifiers_query(int format EINA_UNUSED,uint64_t ** modifiers EINA_UNUSED,int * num_modifiers)1212 e_pixmap_dmabuf_modifiers_query(int format EINA_UNUSED, uint64_t **modifiers EINA_UNUSED, int *num_modifiers)
1213 {
1214    *num_modifiers = 0;
1215 
1216    return EINA_TRUE;
1217 }
1218 
1219 #endif
1220