1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 
4 #include "Evas_Engine_Software_X11.h"
5 #include "evas_engine.h"
6 
7 #include "evas_xlib_outbuf.h"
8 #include "evas_xlib_buffer.h"
9 #include "evas_xlib_swapbuf.h"
10 #include "evas_xlib_color.h"
11 #include "evas_xlib_image.h"
12 #include "evas_xlib_dri_image.h"
13 #include "evas_x_egl.h"
14 
15 #include "../software_generic/evas_native_common.h"
16 
17 #ifdef HAVE_DLSYM
18 # include <dlfcn.h>
19 #endif
20 
21 #include <Ecore.h>
22 #include <Eina.h>
23 
24 static Evas_Native_Tbm_Surface_Image_Set_Call glsym__evas_native_tbm_surface_image_set = NULL;
25 static Evas_Native_Tbm_Surface_Stride_Get_Call glsym__evas_native_tbm_surface_stride_get = NULL;
26 int _evas_engine_soft_x11_log_dom = -1;
27 
28 /* function tables - filled in later (func and parent func) */
29 static Evas_Func func, pfunc;
30 
31 /* engine struct data */
32 typedef struct _Render_Engine Render_Engine;
33 
34 struct _Render_Engine
35 {
36    Render_Output_Software_Generic generic;
37    Eina_Bool                      (*outbuf_alpha_get)(Outbuf *ob);
38 
39    struct
40    {
41       void *disp;
42       void *config;
43       void *surface;
44    } egl;
45 };
46 
47 /* prototypes we will use here */
48 static void        *_best_visual_get(int backend, void *connection, int screen);
49 static unsigned int _best_colormap_get(int backend, void *connection, int screen);
50 static int          _best_depth_get(int backend, void *connection, int screen);
51 
52 static Eina_List *_outbufs = NULL;
53 
54 /* internal engine routines */
55 static void
_output_egl_shutdown(Render_Engine * re)56 _output_egl_shutdown(Render_Engine *re)
57 {
58    if (!re->egl.disp) return;
59    _egl_x_win_surf_free(re->egl.disp, re->egl.surface);
60    _egl_x_disp_terminate(re->egl.disp);
61 }
62 
63 static void *
_output_xlib_setup(void * engine,int w,int h,int rot,Display * disp,Drawable draw,Visual * vis,Colormap cmap,int depth,int debug,int grayscale,int max_colors,Pixmap mask,int shape_dither,int destination_alpha)64 _output_xlib_setup(void *engine, int w, int h, int rot, Display *disp, Drawable draw,
65                    Visual *vis, Colormap cmap, int depth, int debug,
66                    int grayscale, int max_colors, Pixmap mask,
67                    int shape_dither, int destination_alpha)
68 {
69    Render_Engine *re;
70    Outbuf *ob;
71 
72    if (!(re = calloc(1, sizeof(Render_Engine)))) return NULL;
73 
74    evas_software_xlib_x_init();
75    evas_software_xlib_x_color_init();
76    evas_software_xlib_outbuf_init();
77 
78    ob =
79      evas_software_xlib_outbuf_setup_x(w, h, rot, OUTBUF_DEPTH_INHERIT, disp,
80                                        draw, vis, cmap, depth, grayscale,
81                                        max_colors, mask, shape_dither,
82                                        destination_alpha);
83    if (!ob) goto on_error;
84 
85    /* for updates return 1 big buffer, but only use portions of it, also cache
86     * it and keepit around until an idle_flush */
87 
88    /* disable for now - i am hunting down why some expedite tests are slower,
89     * as well as shaped stuff is broken and probable non-32bpp is broken as
90     * convert funcs dont do the right thing
91     *
92     */
93 //   re->ob->onebuf = 1;
94 
95    evas_software_xlib_outbuf_debug_set(ob, debug);
96    if (!evas_render_engine_software_generic_init(engine, &re->generic, ob, NULL,
97                                                  evas_software_xlib_outbuf_get_rot,
98                                                  evas_software_xlib_outbuf_reconfigure,
99                                                  NULL,
100                                                  NULL,
101                                                  evas_software_xlib_outbuf_new_region_for_update,
102                                                  evas_software_xlib_outbuf_push_updated_region,
103                                                  NULL,
104                                                  evas_software_xlib_outbuf_idle_flush,
105                                                  evas_software_xlib_outbuf_flush,
106                                                  NULL,
107                                                  evas_software_xlib_outbuf_free,
108                                                  w, h))
109      goto on_error;
110 
111    evas_render_engine_software_generic_merge_mode_set(&re->generic);
112 
113    return re;
114 
115 on_error:
116    if (ob) evas_software_xlib_outbuf_free(ob);
117    free(re);
118    return NULL;
119 }
120 
121 static void *
_output_swapbuf_setup(void * engine,int w,int h,int rot,Display * disp,Drawable draw,Visual * vis,Colormap cmap,int depth,int debug EINA_UNUSED,int grayscale,int max_colors,Pixmap mask,int shape_dither,int destination_alpha)122 _output_swapbuf_setup(void *engine, int w, int h, int rot, Display *disp, Drawable draw,
123                       Visual *vis, Colormap cmap, int depth,
124                       int debug EINA_UNUSED,
125                       int grayscale, int max_colors, Pixmap mask,
126                       int shape_dither, int destination_alpha)
127 {
128    Render_Engine *re;
129    Outbuf *ob;
130 
131    if (!(re = calloc(1, sizeof(Render_Engine)))) return NULL;
132 
133    evas_software_xlib_x_init();
134    evas_software_xlib_x_color_init();
135    evas_software_xlib_swapbuf_init();
136 
137    ob =
138      evas_software_xlib_swapbuf_setup_x(w, h, rot, OUTBUF_DEPTH_INHERIT, disp,
139                                         draw, vis, cmap, depth, grayscale,
140                                         max_colors, mask, shape_dither,
141                                         destination_alpha);
142    if (!ob) goto on_error;
143 
144    if (!evas_render_engine_software_generic_init(engine, &re->generic, ob,
145                                                  evas_software_xlib_swapbuf_buffer_state_get,
146                                                  evas_software_xlib_swapbuf_get_rot,
147                                                  evas_software_xlib_swapbuf_reconfigure,
148                                                  NULL,
149                                                  NULL,
150                                                  evas_software_xlib_swapbuf_new_region_for_update,
151                                                  evas_software_xlib_swapbuf_push_updated_region,
152                                                  NULL,
153                                                  evas_software_xlib_swapbuf_idle_flush,
154                                                  evas_software_xlib_swapbuf_flush,
155                                                  NULL,
156                                                  evas_software_xlib_swapbuf_free,
157                                                  w, h))
158      goto on_error;
159    return re;
160 
161 on_error:
162    if (ob) evas_software_xlib_swapbuf_free(ob);
163    free(re);
164    return NULL;
165 }
166 
167 static void *
_best_visual_get(int backend,void * connection,int screen)168 _best_visual_get(int backend, void *connection, int screen)
169 {
170    if (!connection) return NULL;
171 
172    if (backend == EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB)
173      return DefaultVisual((Display *)connection, screen);
174 
175    return NULL;
176 }
177 
178 static unsigned int
_best_colormap_get(int backend,void * connection,int screen)179 _best_colormap_get(int backend, void *connection, int screen)
180 {
181    if (!connection) return 0;
182 
183    if (backend == EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB)
184      return DefaultColormap((Display *)connection, screen);
185    return 0;
186 }
187 
188 static int
_best_depth_get(int backend,void * connection,int screen)189 _best_depth_get(int backend, void *connection, int screen)
190 {
191    if (!connection) return 0;
192 
193    if (backend == EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB)
194      return DefaultDepth((Display *)connection, screen);
195    return 0;
196 }
197 
198 static void
_symbols(void)199 _symbols(void)
200 {
201    static int done = 0;
202 
203    if (done) return;
204 
205 #define LINK2GENERIC(sym) \
206   glsym_##sym = dlsym(RTLD_DEFAULT, #sym);
207 
208    // Get function pointer to native_common that is now provided through the link of SW_Generic.
209    LINK2GENERIC(_evas_native_tbm_surface_image_set);
210    LINK2GENERIC(_evas_native_tbm_surface_stride_get);
211 
212    done = 1;
213 }
214 
215 /* engine api this module provides */
216 static void
eng_output_info_setup(void * info)217 eng_output_info_setup(void *info)
218 {
219    Evas_Engine_Info_Software_X11 *einfo = info;
220 
221    einfo->info.debug = 0;
222    einfo->info.alloc_grayscale = 0;
223    einfo->info.alloc_colors_max = 216;
224    einfo->func.best_visual_get = _best_visual_get;
225    einfo->func.best_colormap_get = _best_colormap_get;
226    einfo->func.best_depth_get = _best_depth_get;
227    einfo->render_mode = EVAS_RENDER_MODE_BLOCKING;
228 }
229 
230 static void *
eng_output_setup(void * engine,void * in,unsigned int w,unsigned int h)231 eng_output_setup(void *engine, void *in, unsigned int w, unsigned int h)
232 {
233    Evas_Engine_Info_Software_X11 *info = in;
234    Render_Engine *re = NULL;
235    static int try_swapbuf = -1;
236    char *s;
237 
238    if (info->info.backend != EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB)
239      return NULL;
240 
241    if (try_swapbuf == -1)
242      {
243         if ((s = getenv("EVAS_NO_DRI_SWAPBUF")) != NULL)
244           {
245              if (atoi(s) == 1) try_swapbuf = 0;
246              else try_swapbuf = 1;
247           }
248         else try_swapbuf = 1;
249      }
250 
251    if (try_swapbuf)
252      re = _output_swapbuf_setup(engine, w, h,
253                                 info->info.rotation, info->info.connection,
254                                 info->info.drawable, info->info.visual,
255                                 info->info.colormap,
256                                 info->info.depth, info->info.debug,
257                                 info->info.alloc_grayscale,
258                                 info->info.alloc_colors_max,
259                                 info->info.mask, info->info.shape_dither,
260                                 info->info.destination_alpha);
261    if (re) re->outbuf_alpha_get = evas_software_xlib_swapbuf_alpha_get;
262    else
263      {
264         re = _output_xlib_setup(engine, w, h,
265                                 info->info.rotation, info->info.connection,
266                                 info->info.drawable, info->info.visual,
267                                 info->info.colormap,
268                                 info->info.depth, info->info.debug,
269                                 info->info.alloc_grayscale,
270                                 info->info.alloc_colors_max,
271                                 info->info.mask, info->info.shape_dither,
272                                 info->info.destination_alpha);
273         re->outbuf_alpha_get = evas_software_xlib_outbuf_alpha_get;
274      }
275 
276    _outbufs = eina_list_append(_outbufs, re->generic.ob);
277 
278    return re;
279 }
280 
281 static int
eng_output_update(void * engine EINA_UNUSED,void * data,void * in,unsigned int w,unsigned int h)282 eng_output_update(void *engine EINA_UNUSED, void *data, void *in, unsigned int w, unsigned int h)
283 {
284    Evas_Engine_Info_Software_X11 *info = in;
285    Render_Engine *re = data;
286    Outbuf *ob = NULL;
287 
288    if (info->info.backend != EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB)
289      return 0;
290 
291    _outbufs = eina_list_remove(_outbufs, re->generic.ob);
292 
293    if (re->generic.outbuf_free == evas_software_xlib_swapbuf_free)
294      {
295         ob =
296           evas_software_xlib_swapbuf_setup_x(w, h,
297                                              info->info.rotation,
298                                              OUTBUF_DEPTH_INHERIT,
299                                              info->info.connection,
300                                              info->info.drawable,
301                                              info->info.visual,
302                                              info->info.colormap,
303                                              info->info.depth,
304                                              info->info.alloc_grayscale,
305                                              info->info.alloc_colors_max,
306                                              info->info.mask,
307                                              info->info.shape_dither,
308                                              info->info.destination_alpha);
309      }
310    else
311      {
312         ob =
313           evas_software_xlib_outbuf_setup_x(w, h,
314                                             info->info.rotation,
315                                             OUTBUF_DEPTH_INHERIT,
316                                             info->info.connection,
317                                             info->info.drawable,
318                                             info->info.visual,
319                                             info->info.colormap,
320                                             info->info.depth,
321                                             info->info.alloc_grayscale,
322                                             info->info.alloc_colors_max,
323                                             info->info.mask,
324                                             info->info.shape_dither,
325                                             info->info.destination_alpha);
326         if (ob)
327           evas_software_xlib_outbuf_debug_set(ob, info->info.debug);
328      }
329 
330    if (ob)
331      {
332         evas_render_engine_software_generic_update(&re->generic, ob, w, h);
333      }
334 
335    _outbufs = eina_list_append(_outbufs, re->generic.ob);
336 
337    return 1;
338 }
339 
340 static void
eng_output_free(void * engine,void * data)341 eng_output_free(void *engine, void *data)
342 {
343    Render_Engine *re;
344 
345    if ((re = (Render_Engine *)data))
346      {
347         _outbufs = eina_list_remove(_outbufs, re->generic.ob);
348         evas_render_engine_software_generic_clean(engine, &re->generic);
349         _output_egl_shutdown(re);
350         free(re);
351      }
352 }
353 
354 static Eina_Bool
eng_canvas_alpha_get(void * engine)355 eng_canvas_alpha_get(void *engine)
356 {
357    Render_Engine *re;
358 
359    re = (Render_Engine *)engine;
360    return (re->generic.ob->priv.destination_alpha) ||
361           (re->outbuf_alpha_get(re->generic.ob));
362 }
363 
364 static void
_native_evasgl_free(void * image)365 _native_evasgl_free(void *image)
366 {
367    RGBA_Image *im = image;
368    Native *n = im->native.data;
369 
370    im->native.data = NULL;
371    im->native.func.bind = NULL;
372    im->native.func.unbind = NULL;
373    im->native.func.free = NULL;
374    //im->image.data         = NULL;
375    free(n);
376 }
377 
378 static int
eng_image_native_init(void * engine EINA_UNUSED,Evas_Native_Surface_Type type)379 eng_image_native_init(void *engine EINA_UNUSED, Evas_Native_Surface_Type type)
380 {
381    switch (type)
382      {
383 #ifdef GL_GLES
384       case EVAS_NATIVE_SURFACE_TBM:
385         return _evas_native_tbm_init();
386 
387 #endif
388       case EVAS_NATIVE_SURFACE_X11:
389       case EVAS_NATIVE_SURFACE_EVASGL:
390         return 1;
391 
392       default:
393         ERR("Native surface type %d not supported!", type);
394         return 0;
395      }
396 }
397 
398 static void
eng_image_native_shutdown(void * engine EINA_UNUSED,Evas_Native_Surface_Type type)399 eng_image_native_shutdown(void *engine EINA_UNUSED, Evas_Native_Surface_Type type)
400 {
401    switch (type)
402      {
403 #ifdef GL_GLES
404       case EVAS_NATIVE_SURFACE_TBM:
405         _evas_native_tbm_shutdown();
406         return;
407 
408 #endif
409       case EVAS_NATIVE_SURFACE_X11:
410       case EVAS_NATIVE_SURFACE_OPENGL:
411         return;
412 
413       default:
414         ERR("Native surface type %d not supported!", type);
415         return;
416      }
417 }
418 
419 static void *
eng_image_native_set(void * engine,void * image,void * native)420 eng_image_native_set(void *engine, void *image, void *native)
421 {
422    Render_Engine *re = (Render_Engine *)engine;
423    Evas_Native_Surface *ns = native;
424    Image_Entry *ie = image, *ie2 = NULL;
425    RGBA_Image *im = image;
426    int stride;
427 
428    if (!im) return NULL;
429    if (!ns)
430      {
431         if (im->native.data && im->native.func.free)
432           im->native.func.free(im);
433         return NULL;
434      }
435 
436    if (ns->type == EVAS_NATIVE_SURFACE_X11)
437      {
438         if (im->native.data)
439           {
440              //image have native surface already
441              Evas_Native_Surface *ens = im->native.data;
442 
443              if ((ens->type == ns->type) &&
444                  (ens->data.x11.visual == ns->data.x11.visual) &&
445                  (ens->data.x11.pixmap == ns->data.x11.pixmap))
446                return im;
447           }
448      }
449    else if (ns->type == EVAS_NATIVE_SURFACE_TBM)
450      {
451         if (im->native.data)
452           {
453              //image have native surface already
454              Evas_Native_Surface *ens = im->native.data;
455 
456              if ((ens->type == ns->type) &&
457                  (ens->data.tbm.buffer == ns->data.tbm.buffer))
458                return im;
459           }
460      }
461 
462    // Code from software_generic
463    if ((ns->type == EVAS_NATIVE_SURFACE_EVASGL) &&
464        (ns->version == EVAS_NATIVE_SURFACE_VERSION))
465      ie2 = evas_cache_image_data(evas_common_image_cache_get(),
466                                  ie->w, ie->h, ns->data.evasgl.surface, 1,
467                                  EVAS_COLORSPACE_ARGB8888);
468    else if (ns->type == EVAS_NATIVE_SURFACE_TBM)
469      {
470         stride = glsym__evas_native_tbm_surface_stride_get(re->generic.ob, ns);
471         ie2 = evas_cache_image_copied_data(evas_common_image_cache_get(),
472                                            stride, ie->h, NULL, ie->flags.alpha,
473                                            EVAS_COLORSPACE_ARGB8888);
474      }
475    else
476      ie2 = evas_cache_image_data(evas_common_image_cache_get(),
477                                  ie->w, ie->h, NULL, ie->flags.alpha,
478                                  EVAS_COLORSPACE_ARGB8888);
479 
480    if (im->native.data)
481      {
482         if (im->native.func.free)
483           im->native.func.free(im);
484      }
485 
486    evas_cache_image_drop(ie);
487    ie = ie2;
488 
489    if (ns->type == EVAS_NATIVE_SURFACE_X11)
490      {
491         RGBA_Image *ret_im = NULL;
492         ret_im = evas_xlib_image_dri_native_set(re->generic.ob, ie, ns);
493         if (!ret_im)
494           ret_im = evas_xlib_image_native_set(re->generic.ob, ie, ns);
495         return ret_im;
496      }
497    else if (ns->type == EVAS_NATIVE_SURFACE_TBM)
498      {
499         return glsym__evas_native_tbm_surface_image_set(re->generic.ob, ie, ns);
500      }
501    else if (ns->type == EVAS_NATIVE_SURFACE_EVASGL)
502      {
503         /* Native contains Evas_Native_Surface. What a mess. */
504         Native *n = calloc(1, sizeof(Native));
505         if (n)
506           {
507              n->ns_data.evasgl.surface = ns->data.evasgl.surface;
508              im = (RGBA_Image *)ie;
509              n->ns.type = EVAS_NATIVE_SURFACE_EVASGL;
510              n->ns.version = EVAS_NATIVE_SURFACE_VERSION;
511              n->ns.data.evasgl.surface = ns->data.evasgl.surface;
512              im->native.data = n;
513              im->native.func.free = _native_evasgl_free;
514              im->native.func.bind = NULL;
515              im->native.func.unbind = NULL;
516           }
517      }
518 
519    return ie;
520 }
521 
522 static void *
eng_image_native_get(void * engine EINA_UNUSED,void * image)523 eng_image_native_get(void *engine EINA_UNUSED, void *image)
524 {
525    RGBA_Image *im = image;
526    Native *n;
527    if (!im) return NULL;
528    n = im->native.data;
529    if (!n) return NULL;
530    return &(n->ns);
531 }
532 
533 /* module advertising code */
534 static int
module_open(Evas_Module * em)535 module_open(Evas_Module *em)
536 {
537    if (!em) return 0;
538 
539    /* get whatever engine module we inherit from */
540    if (!_evas_module_engine_inherit(&pfunc, "software_generic", sizeof (Evas_Engine_Info_Software_X11))) return 0;
541 
542    _evas_engine_soft_x11_log_dom =
543      eina_log_domain_register("evas-software_x11", EVAS_DEFAULT_LOG_COLOR);
544 
545    if (_evas_engine_soft_x11_log_dom < 0)
546      {
547         EINA_LOG_ERR("Can not create a module log domain.");
548         return 0;
549      }
550 
551    /* store it for later use */
552    func = pfunc;
553 
554    /* now to override methods */
555 #define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_)
556    ORD(output_info_setup);
557    ORD(output_setup);
558    ORD(output_update);
559    ORD(canvas_alpha_get);
560    ORD(output_free);
561    ORD(image_native_init);
562    ORD(image_native_shutdown);
563    ORD(image_native_set);
564    ORD(image_native_get);
565 
566    _symbols();
567    /* now advertise out own api */
568    em->functions = (void *)(&func);
569    return 1;
570 }
571 
572 static void
module_close(Evas_Module * em EINA_UNUSED)573 module_close(Evas_Module *em EINA_UNUSED)
574 {
575    if (_evas_engine_soft_x11_log_dom >= 0)
576      {
577         eina_log_domain_unregister(_evas_engine_soft_x11_log_dom);
578         _evas_engine_soft_x11_log_dom = -1;
579      }
580 }
581 
582 static Evas_Module_Api evas_modapi =
583 {
584    EVAS_MODULE_API_VERSION, "software_x11", "none",
585    {
586       module_open,
587       module_close
588    }
589 };
590 
591 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, software_x11);
592 
593 #ifndef EVAS_STATIC_BUILD_SOFTWARE_X11
594 EVAS_EINA_MODULE_DEFINE(engine, software_x11);
595 #endif
596