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