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