1 #include "evas_engine.h"
2 #include "../gl_common/evas_gl_define.h"
3 #include <dlfcn.h>
4 
5 # define SET_RESTORE_CONTEXT() do { if (glsym_evas_gl_common_context_restore_set) glsym_evas_gl_common_context_restore_set(EINA_TRUE); } while(0)
6 
7 static Eina_TLS _outbuf_key = 0;
8 static Eina_TLS _context_key = 0;
9 
10 typedef void (*glsym_func_void) ();
11 glsym_func_void glsym_evas_gl_common_context_restore_set = NULL;
12 
13 Eina_Bool gles3_supported = EINA_FALSE;
14 
15 #ifdef GL_GLES
16 typedef EGLContext GLContext;
17 typedef EGLConfig GLConfig;
18 static Eina_Bool gles3_probed = EINA_FALSE;
19 #else
20 // FIXME: this will only work for 1 display connection (glx land can have > 1)
21 typedef GLXContext GLContext;
22 typedef GLXFBConfig GLConfig;
23 static Eina_TLS _rgba_context_key = 0;
24 #endif
25 
26 typedef struct _Evas_GL_X11_Visual Evas_GL_X11_Visual;
27 struct _Evas_GL_X11_Visual
28 {
29    XVisualInfo info;
30    GLConfig config;
31    Colormap cmap;
32    Display *disp;
33    Eina_Bool alpha;
34 };
35 
36 /* index (_visuals_hash_index_get) -> Evas_GL_X11_Visual */
37 static Eina_Hash *_evas_gl_visuals = NULL;
38 
39 static int win_count = 0;
40 static Eina_Bool initted = EINA_FALSE;
41 
42 #if 0
43 static double
44 _time_get(void)
45 {
46    struct timespec t;
47 
48    if (clock_gettime(CLOCK_MONOTONIC, &t))
49      {
50         fprintf(stderr, "Failed to get monotonic clock time...");
51         return 0.0;
52      }
53 
54    return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0);
55 }
56 
57 static void
58 measure(int inout, const char *what)
59 {
60    static double t0 = 0.0;
61    double t;
62 
63    if (inout == 0) t0 = _time_get();
64    else if (inout ==1)
65      {
66         t = _time_get() - t0;
67         printf("%s: %1.2f\n", what, t * 1000.0);
68      }
69 }
70 #else
71 # define measure(x, y)
72 #endif
73 
74 Eina_Bool
eng_init(void)75 eng_init(void)
76 {
77    if (initted)
78      return EINA_TRUE;
79 
80 #define LINK2GENERIC(sym) \
81    glsym_##sym = dlsym(RTLD_DEFAULT, #sym); \
82    if (!glsym_##sym) ERR("Could not find function '%s'", #sym);
83 
84    LINK2GENERIC(evas_gl_common_context_restore_set);
85 
86    // FIXME: These resources are never released
87    if (!eina_tls_new(&_outbuf_key))
88      goto error;
89    if (!eina_tls_new(&_context_key))
90      goto error;
91 
92    eina_tls_set(_outbuf_key, NULL);
93    eina_tls_set(_context_key, NULL);
94 
95 #ifndef GL_GLES
96    if (!eina_tls_new(&_rgba_context_key))
97      goto error;
98    eina_tls_set(_rgba_context_key, NULL);
99 #endif
100 
101    initted = EINA_TRUE;
102    return EINA_TRUE;
103 
104 error:
105    ERR("Could not create TLS key!");
106    return EINA_FALSE;
107 }
108 
109 static inline Outbuf *
_tls_outbuf_get(void)110 _tls_outbuf_get(void)
111 {
112    if (!initted) eng_init();
113    return eina_tls_get(_outbuf_key);
114 }
115 
116 static inline Eina_Bool
_tls_outbuf_set(Outbuf * xwin)117 _tls_outbuf_set(Outbuf *xwin)
118 {
119    if (!initted) eng_init();
120    return eina_tls_set(_outbuf_key, xwin);
121 }
122 
123 static inline GLContext
_tls_context_get(void)124 _tls_context_get(void)
125 {
126    if (!initted) eng_init();
127    return eina_tls_get(_context_key);
128 }
129 
130 static inline Eina_Bool
_tls_context_set(GLContext ctx)131 _tls_context_set(GLContext ctx)
132 {
133    if (!initted) eng_init();
134    return eina_tls_set(_context_key, ctx);
135 }
136 
137 #ifndef GL_GLES
138 static inline GLXContext
_tls_rgba_context_get(void)139 _tls_rgba_context_get(void)
140 {
141    if (!initted) eng_init();
142    return eina_tls_get(_rgba_context_key);
143 }
144 
145 static inline Eina_Bool
_tls_rgba_context_set(GLXContext ctx)146 _tls_rgba_context_set(GLXContext ctx)
147 {
148    if (!initted) eng_init();
149    return eina_tls_set(_rgba_context_key, ctx);
150 }
151 
152 Eina_Bool
__glXMakeContextCurrent(Display * disp,GLXDrawable glxwin,GLXContext context)153 __glXMakeContextCurrent(Display *disp, GLXDrawable glxwin, GLXContext context)
154 {
155    if (!glXMakeContextCurrent(disp, glxwin, glxwin, context)) return EINA_FALSE;
156    return EINA_TRUE;
157 }
158 #endif
159 
160 static void
_visuals_hash_del_cb(void * data)161 _visuals_hash_del_cb(void *data)
162 {
163    Evas_GL_X11_Visual *evis = data;
164    if (evis && evis->cmap && evis->disp)
165      XFreeColormap(evis->disp, evis->cmap);
166    free(evis);
167 }
168 
169 static inline int
_visuals_hash_index_get(int alpha,int zdepth,int stencil,int msaa)170 _visuals_hash_index_get(int alpha, int zdepth, int stencil, int msaa)
171 {
172    if (!_evas_gl_visuals)
173      _evas_gl_visuals = eina_hash_int32_new(_visuals_hash_del_cb);
174    return alpha | (zdepth << 8) | (stencil << 16) | (msaa << 24);
175 }
176 
177 static inline int
_visuals_hash_index_get_from_info(Evas_Engine_Info_GL_X11 * info)178 _visuals_hash_index_get_from_info(Evas_Engine_Info_GL_X11 *info)
179 {
180    if (!info) return -1;
181    return _visuals_hash_index_get(info->info.destination_alpha,
182                                   info->depth_bits, info->stencil_bits,
183                                   info->msaa_bits);
184 }
185 
186 #ifdef GL_GLES
187 
188 static EGLDisplay *
_x11_eglGetDisplay(Display * x11_display)189 _x11_eglGetDisplay(Display *x11_display)
190 {
191    EGLDisplay (*eglsym_eglGetPlatformDisplay)
192          (EGLenum platform, void *native_display, const EGLAttrib *attrib_list) = NULL;
193    EGLDisplay *egldisp = EGL_NO_DISPLAY;
194 
195    eglsym_eglGetPlatformDisplay = dlsym(RTLD_DEFAULT, "eglGetPlatformDisplay");
196    if (eglsym_eglGetPlatformDisplay)
197      {
198         egldisp = eglsym_eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR,
199                                                (EGLNativeDisplayType) x11_display, NULL);
200         if (egldisp) return egldisp;
201      }
202 
203    return eglGetDisplay((EGLNativeDisplayType) x11_display);
204 }
205 
206 #endif
207 
208 Outbuf *
eng_window_new(Evas_Engine_Info_GL_X11 * info,Display * disp,Window win,int screen,Visual * vis,Colormap cmap,int depth,unsigned int w,unsigned int h,int indirect EINA_UNUSED,int alpha,int rot,Render_Output_Swap_Mode swap_mode,int depth_bits,int stencil_bits,int msaa_bits)209 eng_window_new(Evas_Engine_Info_GL_X11 *info,
210                Display *disp,
211                Window   win,
212                int      screen,
213                Visual  *vis,
214                Colormap cmap,
215                int      depth,
216                unsigned int w,
217                unsigned int h,
218                int      indirect EINA_UNUSED,
219                int      alpha,
220                int      rot,
221                Render_Output_Swap_Mode swap_mode,
222                int depth_bits,
223                int stencil_bits,
224                int msaa_bits)
225 {
226    Outbuf *gw;
227    GLContext context;
228 #ifdef GL_GLES
229    int context_attrs[3];
230    int major_version, minor_version;
231 #else
232    GLXContext rgbactx;
233    Evas_GL_X11_Visual *evis2 = NULL;
234    int tmp;
235 #endif
236    const GLubyte *vendor, *renderer, *version, *glslversion;
237    int blacklist = 0;
238    int val = 0, idx;
239    Evas_GL_X11_Visual *evis;
240 
241    idx = _visuals_hash_index_get_from_info(info);
242    evis = eina_hash_find(_evas_gl_visuals, &idx);
243    if (!evis)
244      {
245         eng_best_visual_get(info);
246         evis = eina_hash_find(_evas_gl_visuals, &idx);
247         if (!evis) return NULL;
248      }
249 
250    vis = evis->info.visual;
251    if (!vis) return NULL;
252 
253    gw = calloc(1, sizeof(Outbuf));
254    if (!gw) return NULL;
255 
256    win_count++;
257    gw->disp = disp;
258    gw->win = win;
259    gw->screen = screen;
260    gw->visual = vis;
261    gw->colormap = cmap;
262    gw->depth = depth;
263    gw->alpha = alpha;
264    gw->w = w;
265    gw->h = h;
266    gw->rot = rot;
267    gw->swap_mode = swap_mode;
268    gw->info = info;
269    gw->depth_bits = depth_bits;
270    gw->stencil_bits = stencil_bits;
271    gw->msaa_bits = msaa_bits;
272    gw->visualinfo = &evis->info;
273 
274 // EGL / GLES
275 #ifdef GL_GLES
276    gw->egl_disp = _x11_eglGetDisplay(gw->disp);
277    if (!gw->egl_disp)
278      {
279         ERR("eglGetDisplay() fail. code=%#x", eglGetError());
280         eng_window_free(gw);
281         return NULL;
282      }
283    if (!eglInitialize(gw->egl_disp, &major_version, &minor_version))
284      {
285         ERR("eglInitialize() fail. code=%#x", eglGetError());
286         eng_window_free(gw);
287         return NULL;
288      }
289    if (!eglBindAPI(EGL_OPENGL_ES_API))
290      {
291         ERR("eglBindAPI() fail. code=%#x", eglGetError());
292         eng_window_free(gw);
293         return NULL;
294      }
295 
296    gw->egl_config = evis->config;
297 
298    gw->egl_surface = eglCreateWindowSurface(gw->egl_disp, gw->egl_config,
299                                                (EGLNativeWindowType)gw->win,
300                                                NULL);
301    if (gw->egl_surface == EGL_NO_SURFACE)
302      {
303         int err = eglGetError();
304         printf("surf creat fail! %x\n", err);
305         ERR("eglCreateWindowSurface() fail for %#x. code=%#x",
306             (unsigned int)gw->win, err);
307         eng_window_free(gw);
308         return NULL;
309      }
310 
311 try_gles2:
312    context_attrs[0] = EGL_CONTEXT_CLIENT_VERSION;
313    context_attrs[1] = gles3_supported ? 3 : 2;
314    context_attrs[2] = EGL_NONE;
315 
316    context = _tls_context_get();
317    gw->egl_context = eglCreateContext
318      (gw->egl_disp, gw->egl_config, context, context_attrs);
319    if (gw->egl_context == EGL_NO_CONTEXT)
320      {
321         ERR("eglCreateContext() fail. code=%#x", eglGetError());
322         if (gles3_supported)
323           {
324              /* Note: this shouldn't happen */
325              ERR("Trying again with an Open GL ES 2 context (fallback).");
326              gles3_supported = EINA_FALSE;
327              goto try_gles2;
328           }
329         eng_window_free(gw);
330         return NULL;
331      }
332    if (context == EGL_NO_CONTEXT)
333      _tls_context_set(gw->egl_context);
334 
335    SET_RESTORE_CONTEXT();
336    if (evas_eglMakeCurrent(gw->egl_disp,
337                       gw->egl_surface,
338                       gw->egl_surface,
339                       gw->egl_context) == EGL_FALSE)
340      {
341         ERR("evas_eglMakeCurrent() fail. code=%#x", eglGetError());
342         eng_window_free(gw);
343         return NULL;
344      }
345 
346    vendor = glGetString(GL_VENDOR);
347    renderer = glGetString(GL_RENDERER);
348    version = glGetString(GL_VERSION);
349    glslversion = glGetString(GL_SHADING_LANGUAGE_VERSION);
350    if (!vendor)   vendor   = (unsigned char *)"-UNKNOWN-";
351    if (!renderer) renderer = (unsigned char *)"-UNKNOWN-";
352    if (!version)  version  = (unsigned char *)"-UNKNOWN-";
353    if (!glslversion) glslversion = (unsigned char *)"-UNKNOWN-";
354    if (getenv("EVAS_GL_INFO"))
355      {
356         fprintf(stderr, "vendor  : %s\n", vendor);
357         fprintf(stderr, "renderer: %s\n", renderer);
358         fprintf(stderr, "version : %s\n", version);
359         fprintf(stderr, "glsl ver: %s\n", glslversion);
360      }
361 
362    if (strstr((const char *)vendor, "Mesa Project"))
363      {
364         if (strstr((const char *)renderer, "Software Rasterizer"))
365           blacklist = 1;
366      }
367    if (strstr((const char *)renderer, "softpipe"))
368      blacklist = 1;
369    if (strstr((const char *)renderer, "llvmpipe"))
370      blacklist = 1;
371    if ((blacklist) && (!getenv("EVAS_GL_NO_BLACKLIST")))
372      {
373         WRN("OpenGL Driver blacklisted:");
374         WRN("Vendor: %s", (const char *)vendor);
375         WRN("Renderer: %s", (const char *)renderer);
376         WRN("Version: %s", (const char *)version);
377         eng_window_free(gw);
378         return NULL;
379      }
380    // nvidia drivers in egl/gles mode dont need re-creating of the
381    // eglimage ... and doign so is super slow on them, so avoid the
382    // multi buffer path - as it's only for nvidia and this fixes
383    // the performance regression there, it's fairly safe to do
384    // as it's not universal across all drivers.
385    if (strstr((const char *)vendor, "NVIDIA"))
386      gw->detected.no_multi_buffer_native = 1;
387 
388    eglGetConfigAttrib(gw->egl_disp, gw->egl_config, EGL_DEPTH_SIZE, &val);
389    gw->detected.depth_buffer_size = val;
390    DBG("Detected depth size %d", val);
391    eglGetConfigAttrib(gw->egl_disp, gw->egl_config, EGL_STENCIL_SIZE, &val);
392    gw->detected.stencil_buffer_size = val;
393    DBG("Detected stencil size %d", val);
394    eglGetConfigAttrib(gw->egl_disp, gw->egl_config, EGL_SAMPLES, &val);
395    gw->detected.msaa = val;
396    DBG("Detected msaa %d", val);
397 
398 // GLX
399 #else
400    context = _tls_context_get();
401    if (!context)
402      {
403         if (!evis->alpha)
404           evis2 = evis;
405         else
406           {
407              tmp = info->info.destination_alpha;
408              info->info.destination_alpha = 0;
409              evis2 = eng_best_visual_get(info);
410              info->info.destination_alpha = tmp;
411              if (!evis2)
412                {
413                   ERR("Could not find visual! (rgb only)");
414                   evis2 = evis;
415                }
416           }
417         if (indirect)
418           context = glXCreateNewContext(gw->disp, evis2->config,
419                                         GLX_RGBA_TYPE, NULL,
420                                         GL_FALSE);
421         else
422           context = glXCreateNewContext(gw->disp, evis2->config,
423                                         GLX_RGBA_TYPE, NULL,
424                                         GL_TRUE);
425         _tls_context_set(context);
426      }
427    rgbactx = _tls_rgba_context_get();
428    if ((gw->alpha) && (!rgbactx))
429      {
430         if (evis->alpha)
431           evis2 = evis;
432         else
433           {
434              tmp = info->info.destination_alpha;
435              info->info.destination_alpha = 1;
436              evis2 = eng_best_visual_get(info);
437              info->info.destination_alpha = tmp;
438              if (!evis2)
439                {
440                   ERR("Could not find visual! (rgba)");
441                   evis2 = evis;
442                }
443           }
444         if (indirect)
445           rgbactx = glXCreateNewContext(gw->disp, evis2->config,
446                                         GLX_RGBA_TYPE, context,
447                                         GL_FALSE);
448         else
449           rgbactx = glXCreateNewContext(gw->disp, evis2->config,
450                                         GLX_RGBA_TYPE, context,
451                                         GL_TRUE);
452         _tls_rgba_context_set(rgbactx);
453      }
454 
455    if (gw->alpha != info->info.destination_alpha)
456      {
457         tmp = info->info.destination_alpha;
458         info->info.destination_alpha = gw->alpha;
459         evis2 = eng_best_visual_get(info);
460         info->info.destination_alpha = tmp;
461         if (!evis2)
462           {
463              ERR("Could not find visual! (alpha: %d)", gw->alpha);
464              evis2 = evis;
465           }
466      }
467    else
468      evis2 = evis;
469    gw->glxwin = glXCreateWindow(gw->disp, evis2->config, gw->win, NULL);
470 
471    if (!gw->glxwin)
472      {
473         ERR("glXCreateWindow failed.");
474         eng_window_free(gw);
475         return NULL;
476      }
477 
478    if (gw->alpha) gw->context = rgbactx;
479    else gw->context = context;
480 
481    if (!gw->context)
482      {
483         ERR("Failed to create a context.");
484         eng_window_free(gw);
485         return NULL;
486      }
487    if (!__glXMakeContextCurrent(gw->disp, gw->glxwin, gw->context))
488      {
489         ERR("glXMakeContextCurrent(%p, %p, %p, %p)\n", (void *)gw->disp, (void *)gw->glxwin, (void *)gw->win, (void *)gw->context);
490         eng_window_free(gw);
491         return NULL;
492      }
493    // FIXME: move this up to context creation
494 
495    vendor = glGetString(GL_VENDOR);
496    renderer = glGetString(GL_RENDERER);
497    version = glGetString(GL_VERSION);
498    glslversion = glGetString(GL_SHADING_LANGUAGE_VERSION);
499    if (!vendor)   vendor   = (unsigned char *)"-UNKNOWN-";
500    if (!renderer) renderer = (unsigned char *)"-UNKNOWN-";
501    if (!version)  version  = (unsigned char *)"-UNKNOWN-";
502    if (!glslversion) glslversion = (unsigned char *)"-UNKNOWN-";
503    if (getenv("EVAS_GL_INFO"))
504      {
505         fprintf(stderr, "vendor  : %s\n", vendor);
506         fprintf(stderr, "renderer: %s\n", renderer);
507         fprintf(stderr, "version : %s\n", version);
508         fprintf(stderr, "glsl ver: %s\n", glslversion);
509      }
510 
511    //   examples:
512    // vendor: NVIDIA Corporation
513    // renderer: NVIDIA Tegra
514    // version: OpenGL ES 2.0
515    //   or
516    // vendor: Imagination Technologies
517    // renderer: PowerVR SGX 540
518    // version: OpenGL ES 2.0
519    //   or
520    // vendor: NVIDIA Corporation
521    // renderer: GeForce GT 330M/PCI/SSE2
522    // version: 3.3.0 NVIDIA 256.53
523    //   or
524    // vendor: NVIDIA Corporation
525    // renderer: GeForce GT 220/PCI/SSE2
526    // version: 3.2.0 NVIDIA 195.36.24
527    //   or
528    // vendor: NVIDIA Corporation
529    // renderer: GeForce 8600 GTS/PCI/SSE2
530    // version: 3.3.0 NVIDIA 260.19.36
531    //   or
532    // vendor: ATI Technologies Inc.
533    // renderer: ATI Mobility Radeon HD 4650
534    // version: 3.2.9756 Compatibility Profile Context
535    //   or
536    // vendor: Tungsten Graphics, Inc
537    // renderer: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2
538    // version: 2.1 Mesa 7.9-devel
539    //   or
540    // vendor: Advanced Micro Devices, Inc.
541    // renderer: Mesa DRI R600 (RS780 9610) 20090101  TCL DRI2
542    // version: 2.1 Mesa 7.9-devel
543    //   or
544    // vendor: NVIDIA Corporation
545    // renderer: GeForce 9600 GT/PCI/SSE2
546    // version: 3.3.0 NVIDIA 260.19.29
547    //   or
548    // vendor: ATI Technologies Inc.
549    // renderer: ATI Radeon HD 4800 Series
550    // version: 3.3.10237 Compatibility Profile Context
551    //   or
552    // vendor: Advanced Micro Devices, Inc.
553    // renderer: Mesa DRI R600 (RV770 9442) 20090101  TCL DRI2
554    // version: 2.0 Mesa 7.8.2
555    //   or
556    // vendor: Tungsten Graphics, Inc
557    // renderer: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100330 DEVELOPMENT
558    // version: 2.1 Mesa 7.9-devel
559    //   or (bad - software renderer)
560    // vendor: Mesa Project
561    // renderer: Software Rasterizer
562    // version: 2.1 Mesa 7.9-devel
563    //   or (bad - software renderer)
564    // vendor: VMware, Inc.
565    // renderer: Gallium 0.4 on softpipe
566    // version: 2.1 Mesa 7.9-devel
567    //
568    if (strstr((const char *)vendor, "Mesa Project"))
569      {
570         if (strstr((const char *)renderer, "Software Rasterizer"))
571           blacklist = 1;
572      }
573    if (strstr((const char *)renderer, "softpipe"))
574      blacklist = 1;
575    if (strstr((const char *)renderer, "llvmpipe"))
576      blacklist = 1;
577    if ((blacklist) && (!getenv("EVAS_GL_NO_BLACKLIST")))
578      {
579         WRN("OpenGL Driver blacklisted:");
580         WRN("Vendor: %s", (const char *)vendor);
581         WRN("Renderer: %s", (const char *)renderer);
582         WRN("Version: %s", (const char *)version);
583         eng_window_free(gw);
584         return NULL;
585      }
586    if (strstr((const char *)vendor, "NVIDIA"))
587      {
588         if (!strstr((const char *)renderer, "NVIDIA Tegra"))
589           {
590              int v1 = 0, v2 = 0, v3 = 0;
591 
592              if (sscanf((const char *)version,
593                         "%*s %*s %i.%i.%i",
594                         &v1, &v2, &v3) != 3)
595                {
596                   v1 = v2 = v3 = 0;
597                   if (sscanf((const char *)version,
598                              "%*s %*s %i.%i",
599                              &v1, &v2) != 2)
600                     v1 = 0;
601                }
602              // ALSO as of some nvidia driver version loose binding is
603              // probably not needed
604              if (v1 < 195) gw->detected.loose_binding = 1;
605           }
606      }
607    else
608      {
609         // noothing yet. add more cases and options over time
610      }
611 
612    glXGetConfig(gw->disp, gw->visualinfo, GLX_DEPTH_SIZE, &val);
613    gw->detected.depth_buffer_size = val;
614    glXGetConfig(gw->disp, gw->visualinfo, GLX_STENCIL_SIZE, &val);
615    gw->detected.stencil_buffer_size = val;
616    glXGetConfig(gw->disp, gw->visualinfo, GLX_SAMPLES, &val);
617    gw->detected.msaa = val;
618 #endif
619 
620    eng_gl_symbols(gw);
621    gw->gl_context = glsym_evas_gl_common_context_new();
622    if (!gw->gl_context)
623      {
624         ERR("Unable to get a new context.");
625         eng_window_free(gw);
626         return NULL;
627      }
628 #ifdef GL_GLES
629    gw->gl_context->egldisp = gw->egl_disp;
630    gw->gl_context->eglctxt = gw->egl_context;
631 #else
632    glXGetFBConfigAttrib(gw->disp, evis->config, GLX_FBCONFIG_ID, &gw->gl_context->glxcfg_rgb);
633    glXGetFBConfigAttrib(gw->disp, evis2->config, GLX_FBCONFIG_ID, &gw->gl_context->glxcfg_rgba);
634 #endif
635    gw->gl_context->msaa = (Eina_Bool) !!msaa_bits;
636    eng_window_use(gw);
637    glsym_evas_gl_common_context_resize(gw->gl_context, w, h, rot);
638    gw->surf = 1;
639    return gw;
640 }
641 
642 void
eng_window_free(Outbuf * gw)643 eng_window_free(Outbuf *gw)
644 {
645    Outbuf *xwin;
646    GLContext context;
647    int ref = 0;
648    win_count--;
649    eng_window_use(gw);
650 
651    if (win_count == 0) evas_common_font_ext_clear();
652 
653    context = _tls_context_get();
654    xwin = _tls_outbuf_get();
655 
656    if (gw == xwin) _tls_outbuf_set(NULL);
657    if (gw->gl_context)
658      {
659         ref = gw->gl_context->references - 1;
660         glsym_evas_gl_common_context_free(gw->gl_context);
661      }
662 #ifdef GL_GLES
663    SET_RESTORE_CONTEXT();
664    if (!evas_eglMakeCurrent(gw->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
665      ERR("evas_eglMakeCurrent() failed!");
666    if (gw->egl_surface != EGL_NO_SURFACE)
667      eglDestroySurface(gw->egl_disp, gw->egl_surface);
668    if (gw->egl_context != context)
669      eglDestroyContext(gw->egl_disp, gw->egl_context);
670    if (ref == 0)
671      {
672         if (context) eglDestroyContext(gw->egl_disp, context);
673         eina_hash_free(_evas_gl_visuals);
674         _evas_gl_visuals = NULL;
675         eglTerminate(gw->egl_disp);
676         eglReleaseThread();
677         _tls_context_set(EGL_NO_CONTEXT);
678      }
679 #else
680    glXDestroyWindow(gw->disp, gw->glxwin);
681    if (ref == 0)
682      {
683         GLXContext rgbactx = _tls_rgba_context_get();
684         if (context) glXDestroyContext(gw->disp, context);
685         if (rgbactx) glXDestroyContext(gw->disp, rgbactx);
686         eina_hash_free(_evas_gl_visuals);
687         _evas_gl_visuals = NULL;
688         _tls_context_set(0);
689         _tls_rgba_context_set(0);
690      }
691 #endif
692    free(gw);
693 }
694 
695 static Eina_Bool
eng_window_make_current(void * data,void * doit)696 eng_window_make_current(void *data, void *doit)
697 {
698    Outbuf *gw = data;
699 
700 #ifdef GL_GLES
701    SET_RESTORE_CONTEXT();
702    if (doit)
703      {
704         if (!evas_eglMakeCurrent(gw->egl_disp, gw->egl_surface, gw->egl_surface, gw->egl_context))
705           return EINA_FALSE;
706      }
707    else
708      {
709         if (!evas_eglMakeCurrent(gw->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
710           return EINA_FALSE;
711      }
712 #else
713    if (doit)
714      {
715         if (!__glXMakeContextCurrent(gw->disp, gw->glxwin, gw->context))
716           {
717              ERR("glXMakeContextCurrent(%p, %p, %p, %p)", (void *)gw->disp, (void *)gw->glxwin, (void *)gw->win, (void *)gw->context);
718              return EINA_FALSE;
719           }
720      }
721    else
722      {
723         if (!__glXMakeContextCurrent(gw->disp, 0, NULL))
724           return EINA_FALSE;
725      }
726 #endif
727    return EINA_TRUE;
728 }
729 
730 void
eng_window_use(Outbuf * gw)731 eng_window_use(Outbuf *gw)
732 {
733    Eina_Bool force_use = EINA_FALSE;
734    Outbuf *xwin;
735 
736    xwin = _tls_outbuf_get();
737 
738    glsym_evas_gl_preload_render_lock(eng_window_make_current, gw);
739    if ((gw) && (!gw->gl_context)) return;
740 
741 #ifdef GL_GLES
742    if (xwin)
743      {
744         if ((evas_eglGetCurrentDisplay() != xwin->egl_disp) ||
745             (evas_eglGetCurrentContext() != xwin->egl_context))
746           force_use = EINA_TRUE;
747      }
748 #else
749    if (xwin)
750      {
751         if (glXGetCurrentContext() != xwin->context)
752            force_use = EINA_TRUE;
753      }
754 #endif
755    if ((xwin != gw) || (force_use))
756      {
757         if (xwin)
758           {
759              glsym_evas_gl_common_context_use(xwin->gl_context);
760              glsym_evas_gl_common_context_flush(xwin->gl_context);
761           }
762         _tls_outbuf_set(gw);
763         if (gw)
764           {
765 // EGL / GLES
766 #ifdef GL_GLES
767              if (gw->egl_surface != EGL_NO_SURFACE)
768                {
769                   SET_RESTORE_CONTEXT();
770                   if (evas_eglMakeCurrent(gw->egl_disp,
771                                      gw->egl_surface,
772                                      gw->egl_surface,
773                                      gw->egl_context) == EGL_FALSE)
774                     {
775                        ERR("evas_eglMakeCurrent() failed!");
776                     }
777                }
778 // GLX
779 #else
780              if (!__glXMakeContextCurrent(gw->disp, gw->glxwin, gw->context))
781                {
782                   ERR("glXMakeContextCurrent(%p, %p, %p, %p)", (void *)gw->disp, (void *)gw->glxwin, (void *)gw->win, (void *)gw->context);
783                }
784 #endif
785           }
786      }
787    if (gw) glsym_evas_gl_common_context_use(gw->gl_context);
788 }
789 
790 void
eng_window_unsurf(Outbuf * gw)791 eng_window_unsurf(Outbuf *gw)
792 {
793    if (!gw->surf) return;
794    if (!getenv("EVAS_GL_WIN_RESURF")) return;
795    if (getenv("EVAS_GL_INFO")) printf("unsurf %p\n", gw);
796 
797 #ifdef GL_GLES
798    Outbuf *xwin;
799 
800    xwin = _tls_outbuf_get();
801    if (xwin)
802       glsym_evas_gl_common_context_flush(xwin->gl_context);
803    if (xwin == gw)
804      {
805         SET_RESTORE_CONTEXT();
806         if (!evas_eglMakeCurrent(gw->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
807           ERR("evas_eglMakeCurrent() failed!");
808         if (gw->egl_surface != EGL_NO_SURFACE)
809           eglDestroySurface(gw->egl_disp, gw->egl_surface);
810         gw->egl_surface = EGL_NO_SURFACE;
811         _tls_outbuf_set(NULL);
812      }
813 #else
814    if (gw->glxwin)
815      {
816         glXDestroyWindow(gw->disp, gw->glxwin);
817         gw->glxwin = 0;
818      }
819 #endif
820    gw->surf = 0;
821 }
822 
823 void
eng_window_resurf(Outbuf * gw)824 eng_window_resurf(Outbuf *gw)
825 {
826    if (gw->surf) return;
827    if (getenv("EVAS_GL_INFO")) printf("resurf %p\n", gw);
828 #ifdef GL_GLES
829    if (gw->egl_surface)
830      eglDestroySurface(gw->egl_disp, gw->egl_surface);
831    gw->egl_surface = eglCreateWindowSurface(gw->egl_disp, gw->egl_config,
832                                                (EGLNativeWindowType)gw->win,
833                                                NULL);
834    if (gw->egl_surface == EGL_NO_SURFACE)
835      {
836         ERR("eglCreateWindowSurface() fail for %#x. code=%#x",
837             (unsigned int)gw->win, eglGetError());
838         return;
839      }
840    SET_RESTORE_CONTEXT();
841    if (evas_eglMakeCurrent(gw->egl_disp,
842                       gw->egl_surface,
843                       gw->egl_surface,
844                       gw->egl_context) == EGL_FALSE)
845      {
846         ERR("evas_eglMakeCurrent() failed!");
847      }
848 #else
849    Evas_GL_X11_Visual *evis;
850    int idx = _visuals_hash_index_get(gw->alpha, gw->depth_bits, gw->stencil_bits, gw->msaa_bits);
851    evis = eina_hash_find(_evas_gl_visuals, &idx);
852    if (!evis)
853      {
854         eng_best_visual_get(gw->info);
855         evis = eina_hash_find(_evas_gl_visuals, &idx);
856         if (!evis)
857           {
858              ERR("Could not find matching visual! Resurf failed.");
859              return;
860           }
861      }
862    gw->glxwin = glXCreateWindow(gw->disp, evis->config, gw->win, NULL);
863    if (!__glXMakeContextCurrent(gw->disp, gw->glxwin, gw->context))
864      {
865         ERR("glXMakeContextCurrent(%p, %p, %p, %p)", (void *)gw->disp, (void *)gw->glxwin, (void *)gw->win, (void *)gw->context);
866      }
867 #endif
868    gw->surf = 1;
869 }
870 
871 void *
eng_best_visual_get(Evas_Engine_Info_GL_X11 * einfo)872 eng_best_visual_get(Evas_Engine_Info_GL_X11 *einfo)
873 {
874    Evas_GL_X11_Visual *evis;
875    int alpha;
876    int depth_bits;
877    int stencil_bits;
878    int msaa_samples;
879    int config_attrs[40], i, num, idx;
880    Eina_Bool found;
881 
882    if (!einfo) return NULL;
883    if (!einfo->info.display) return NULL;
884 
885    alpha = einfo->info.destination_alpha;
886    depth_bits = einfo->depth_bits;
887    stencil_bits = einfo->stencil_bits;
888    msaa_samples = einfo->msaa_bits;
889 
890    idx = _visuals_hash_index_get_from_info(einfo);
891    evis = eina_hash_find(_evas_gl_visuals, &idx);
892    if (evis)
893      return evis->info.visual;
894 
895    evis = calloc(1, sizeof(Evas_GL_X11_Visual));
896    if (!evis) return NULL;
897 
898    evis->alpha = alpha;
899 
900    // EGL / GLES
901 #ifdef GL_GLES
902    EGLDisplay *egl_disp;
903    EGLConfig configs[200];
904    int major_version, minor_version;
905    const char *eglexts, *s;
906    int depth = DefaultDepth(einfo->info.display, einfo->info.screen);
907 
908    egl_disp = _x11_eglGetDisplay(einfo->info.display);
909    if (!egl_disp)
910      {
911         free(evis);
912         return NULL;
913      }
914    if (!eglInitialize(egl_disp, &major_version, &minor_version))
915      {
916         free(evis);
917         return NULL;
918      }
919 
920    /* detect GLES 3.x support */
921    if (gles3_probed == EINA_FALSE)
922      {
923         gles3_probed = EINA_TRUE;
924         eglexts = eglQueryString(egl_disp, EGL_EXTENSIONS);
925         if (eglexts && strstr(eglexts, "EGL_KHR_create_context"))
926           {
927              int k, numconfigs = 0, value;
928              EGLConfig *eglconfigs;
929 
930              if (eglGetConfigs(egl_disp, NULL, 0, &numconfigs) &&
931                  (numconfigs > 0))
932                {
933                   eglconfigs = alloca(numconfigs * sizeof(EGLConfig));
934                   eglGetConfigs(egl_disp, eglconfigs, numconfigs, &numconfigs);
935                   for (k = 0; k < numconfigs; k++)
936                     {
937                        value = 0;
938                        if (eglGetConfigAttrib(egl_disp, eglconfigs[k], EGL_RENDERABLE_TYPE, &value) &&
939                            ((value & EGL_OPENGL_ES3_BIT_KHR) != 0) &&
940                            eglGetConfigAttrib(egl_disp, eglconfigs[k], EGL_SURFACE_TYPE, &value) &&
941                            ((value & EGL_WINDOW_BIT) != 0))
942                          {
943                             INF("OpenGL ES 3.x is supported!");
944                             gles3_supported = EINA_TRUE;
945                             break;
946                          }
947                     }
948                }
949           }
950 
951         if (gles3_supported &&
952             ((s = getenv("EVAS_GL_DISABLE_GLES3")) && (atoi(s) == 1)))
953           {
954              INF("Disabling OpenGL ES 3.x support.");
955              gles3_supported = EINA_FALSE;
956           }
957      }
958 
959    /* Find matching config & visual */
960 try_again:
961    i = 0;
962    config_attrs[i++] = EGL_SURFACE_TYPE;
963    config_attrs[i++] = EGL_WINDOW_BIT;
964    config_attrs[i++] = EGL_RENDERABLE_TYPE;
965    if (gles3_supported)
966      config_attrs[i++] = EGL_OPENGL_ES3_BIT_KHR;
967    else
968      config_attrs[i++] = EGL_OPENGL_ES2_BIT;
969 # if 0
970    // FIXME: n900 - omap3 sgx libs break here
971    config_attrs[n++] = EGL_RED_SIZE;
972    config_attrs[n++] = 1;
973    config_attrs[n++] = EGL_GREEN_SIZE;
974    config_attrs[n++] = 1;
975    config_attrs[n++] = EGL_BLUE_SIZE;
976    config_attrs[n++] = 1;
977    // FIXME: end n900 breakage
978 # endif
979    config_attrs[i++] = EGL_ALPHA_SIZE;
980    config_attrs[i++] = (alpha ? 1 : 0);
981 
982    if (depth_bits)
983      {
984         config_attrs[i++] = EGL_DEPTH_SIZE;
985         config_attrs[i++] = depth_bits;
986      }
987 
988    if (stencil_bits)
989      {
990         config_attrs[i++] = EGL_STENCIL_SIZE;
991         config_attrs[i++] = stencil_bits;
992      }
993 
994    if (msaa_samples)
995      {
996         config_attrs[i++] = EGL_SAMPLE_BUFFERS;
997         config_attrs[i++] = 1;
998         config_attrs[i++] = EGL_SAMPLES;
999         config_attrs[i++] = msaa_samples;
1000      }
1001    config_attrs[i++] = EGL_NONE;
1002    num = 0;
1003    if ((!eglChooseConfig(egl_disp, config_attrs, configs, 200, &num))
1004        || (num < 1))
1005      {
1006         ERR("eglChooseConfig() can't find any configs (gles%d, alpha: %d, depth: %d, stencil: %d, msaa: %d)",
1007             gles3_supported ? 3 : 2, alpha, depth_bits, stencil_bits, msaa_samples);
1008         if ((depth_bits > 24) || (stencil_bits > 8))
1009           {
1010              WRN("Please note that your driver might not support 32-bit depth or "
1011                  "16-bit stencil buffers, so depth24, stencil8 are the maximum "
1012                  "recommended values.");
1013              if (depth_bits > 24) depth_bits = 24;
1014              if (stencil_bits > 8) stencil_bits = 8;
1015              DBG("Trying again with depth:%d, stencil:%d", depth_bits, stencil_bits);
1016              goto try_again;
1017           }
1018         else if (msaa_samples)
1019           {
1020              msaa_samples /= 2;
1021              DBG("Trying again with msaa_samples: %d", msaa_samples);
1022              goto try_again;
1023           }
1024         else if (depth_bits || stencil_bits)
1025           {
1026              depth_bits = 0;
1027              stencil_bits = 0;
1028              DBG("Trying again without any depth or stencil buffer");
1029              goto try_again;
1030           }
1031         free(evis);
1032         return NULL;
1033      }
1034    found = EINA_FALSE;
1035    for (i = 0; (i < num) && (!found); i++)
1036      {
1037         EGLint val = 0;
1038         VisualID visid = 0;
1039         XVisualInfo *xvi, vi_in;
1040         int nvi, j;
1041 
1042         if (!eglGetConfigAttrib(egl_disp, configs[i],
1043                                 EGL_NATIVE_VISUAL_ID, &val))
1044           continue;
1045         visid = val;
1046         vi_in.screen = einfo->info.screen;
1047         vi_in.visualid = visid;
1048         xvi = XGetVisualInfo(einfo->info.display,
1049                              VisualScreenMask |
1050                              VisualIDMask,
1051                              &vi_in, &nvi);
1052         for (j = 0; j < nvi; j++)
1053           {
1054              if (!alpha)
1055                {
1056                   if (xvi[j].depth == depth)
1057                     {
1058                        memcpy(&evis->info, &(xvi[j]), sizeof(XVisualInfo));
1059                        evis->config = configs[i];
1060                        found = EINA_TRUE;
1061                        break;
1062                     }
1063                }
1064              else
1065                {
1066                   XRenderPictFormat *fmt;
1067 
1068                   fmt = XRenderFindVisualFormat
1069                         (einfo->info.display, xvi[j].visual);
1070                   if ((fmt->direct.alphaMask > 0) &&
1071                       (fmt->type == PictTypeDirect))
1072                     {
1073                        memcpy(&evis->info, &(xvi[j]), sizeof(XVisualInfo));
1074                        evis->config = configs[i];
1075                        found = EINA_TRUE;
1076                        break;
1077                     }
1078                }
1079           }
1080         if (xvi) XFree(xvi);
1081      }
1082    if (!found)
1083      {
1084         // this is a less correct fallback if the above fails to
1085         // find the right visuals/configs
1086         if (!alpha)
1087           {
1088              evis->config = configs[0];
1089              XMatchVisualInfo(einfo->info.display,
1090                               einfo->info.screen, depth, TrueColor,
1091                               &evis->info);
1092           }
1093         else
1094           {
1095              XVisualInfo *xvi, vi_in;
1096              int nvi, j;
1097              XRenderPictFormat *fmt;
1098 
1099              evis->config = configs[0];
1100              vi_in.screen = einfo->info.screen;
1101              vi_in.depth = 32;
1102              vi_in.class = TrueColor;
1103              xvi = XGetVisualInfo(einfo->info.display,
1104                                   VisualScreenMask | VisualDepthMask |
1105                                   VisualClassMask,
1106                                   &vi_in, &nvi);
1107              if (xvi)
1108                {
1109                   for (j = 0; j < nvi; j++)
1110                     {
1111                        fmt = XRenderFindVisualFormat(einfo->info.display,
1112                                                      xvi[j].visual);
1113                        if ((fmt->type == PictTypeDirect) &&
1114                            (fmt->direct.alphaMask))
1115                          {
1116                             memcpy(&evis->info, &(xvi[j]), sizeof(XVisualInfo));
1117                             break;
1118                          }
1119                     }
1120                   XFree(xvi);
1121                }
1122           }
1123      }
1124 
1125    // GLX
1126 #else
1127    GLXFBConfig *configs = NULL, config = 0;
1128 
1129 try_again:
1130    i = 0;
1131    config_attrs[i++] = GLX_DRAWABLE_TYPE;
1132    config_attrs[i++] = GLX_WINDOW_BIT;
1133    config_attrs[i++] = GLX_DOUBLEBUFFER;
1134    config_attrs[i++] = 1;
1135    config_attrs[i++] = GLX_RED_SIZE;
1136    config_attrs[i++] = 1;
1137    config_attrs[i++] = GLX_GREEN_SIZE;
1138    config_attrs[i++] = 1;
1139    config_attrs[i++] = GLX_BLUE_SIZE;
1140    config_attrs[i++] = 1;
1141    if (alpha)
1142      {
1143         config_attrs[i++] = GLX_RENDER_TYPE;
1144         config_attrs[i++] = GLX_RGBA_BIT;
1145         config_attrs[i++] = GLX_ALPHA_SIZE;
1146         config_attrs[i++] = 1;
1147      }
1148    else
1149      {
1150         config_attrs[i++] = GLX_ALPHA_SIZE;
1151         config_attrs[i++] = 0;
1152      }
1153    if (depth_bits)
1154      {
1155         config_attrs[i++] = GLX_DEPTH_SIZE;
1156         config_attrs[i++] = depth_bits;
1157      }
1158    if (stencil_bits)
1159      {
1160         config_attrs[i++] = GLX_STENCIL_SIZE;
1161         config_attrs[i++] = stencil_bits;
1162      }
1163    if (msaa_samples)
1164      {
1165         config_attrs[i++] = GLX_SAMPLE_BUFFERS;
1166         config_attrs[i++] = 1;
1167         config_attrs[i++] = GLX_SAMPLES;
1168         config_attrs[i++] = msaa_samples;
1169      }
1170    config_attrs[i++] = GLX_AUX_BUFFERS;
1171    config_attrs[i++] = 0;
1172    config_attrs[i++] = GLX_STEREO;
1173    config_attrs[i++] = 0;
1174    config_attrs[i++] = GLX_TRANSPARENT_TYPE;
1175    config_attrs[i++] = GLX_NONE;//GLX_TRANSPARENT_INDEX,GLX_TRANSPARENT_RGB
1176    config_attrs[i++] = 0;
1177 
1178    configs = glXChooseFBConfig(einfo->info.display,
1179                                einfo->info.screen,
1180                                config_attrs, &num);
1181    if ((!configs) || (num < 1))
1182      {
1183         ERR("glXChooseFBConfig() can't find any configs (alpha: %d, depth: %d, stencil: %d, msaa: %d)",
1184             alpha, depth_bits, stencil_bits, msaa_samples);
1185         if (configs) XFree(configs);
1186         if ((depth_bits > 24) || (stencil_bits > 8))
1187           {
1188              WRN("Please note that your driver might not support 32-bit depth or "
1189                  "16-bit stencil buffers, so depth24, stencil8 are the maximum "
1190                  "recommended values.");
1191              if (depth_bits > 24) depth_bits = 24;
1192              if (stencil_bits > 8) stencil_bits = 8;
1193              DBG("Trying again with depth:%d, stencil:%d", depth_bits, stencil_bits);
1194              goto try_again;
1195           }
1196         else if (msaa_samples)
1197           {
1198              msaa_samples /= 2;
1199              DBG("Trying again with msaa_samples: %d", msaa_samples);
1200              goto try_again;
1201           }
1202         else if (depth_bits || stencil_bits)
1203           {
1204              depth_bits = 0;
1205              stencil_bits = 0;
1206              DBG("Trying again without any depth or stencil buffer");
1207              goto try_again;
1208           }
1209         free(evis);
1210         return NULL;
1211      }
1212 
1213    found = EINA_FALSE;
1214    for (i = 0; (i < num) && !found; i++)
1215      {
1216         XVisualInfo *visinfo;
1217         XRenderPictFormat *format = NULL;
1218 
1219         visinfo = glXGetVisualFromFBConfig(einfo->info.display,
1220                                            configs[i]);
1221         if (!visinfo) continue;
1222         if (visinfo->visual->class != TrueColor)
1223           {
1224              XFree(visinfo);
1225              continue;
1226           }
1227         if (!alpha)
1228           {
1229              config = configs[i];
1230              // ensure depth matches default depth!
1231              if (DefaultDepth(einfo->info.display, 0) ==
1232                  visinfo->depth)
1233                {
1234                   memcpy(&evis->info, visinfo, sizeof(XVisualInfo));
1235                   evis->config = config;
1236                   found = EINA_TRUE;
1237                   XFree(visinfo);
1238                   break;
1239                }
1240           }
1241         else
1242           {
1243              format = XRenderFindVisualFormat
1244                    (einfo->info.display, visinfo->visual);
1245              if (!format)
1246                {
1247                   XFree(visinfo);
1248                   continue;
1249                }
1250              if ((format->direct.alphaMask > 0) &&
1251                  (format->type == PictTypeDirect))
1252                {
1253                   memcpy(&evis->info, visinfo, sizeof(XVisualInfo));
1254                   evis->config = configs[i];
1255                   evis->cmap = format->colormap;
1256                   found = EINA_TRUE;
1257                   XFree(visinfo);
1258                   break;
1259                }
1260           }
1261         XFree(visinfo);
1262      }
1263 
1264    XFree(configs);
1265    if (!found)
1266      {
1267         ERR("Could not find a matching config. Now what?");
1268         free(evis);
1269         return NULL;
1270      }
1271 #endif
1272 
1273    if (!evis->cmap)
1274      {
1275         /* save colormap now */
1276         evis->disp = einfo->info.display;
1277         evis->cmap = XCreateColormap(einfo->info.display,
1278                                     RootWindow(einfo->info.display,
1279                                                einfo->info.screen),
1280                                     evis->info.visual, 0);
1281      }
1282 
1283    eina_hash_add(_evas_gl_visuals, &idx, evis);
1284    return evis->info.visual;
1285 }
1286 
1287 Colormap
eng_best_colormap_get(Evas_Engine_Info_GL_X11 * einfo)1288 eng_best_colormap_get(Evas_Engine_Info_GL_X11 *einfo)
1289 {
1290    Evas_GL_X11_Visual *evis;
1291    int idx;
1292 
1293    if (!einfo) return 0;
1294    if (!einfo->info.display) return 0;
1295    idx = _visuals_hash_index_get_from_info(einfo);
1296    evis = eina_hash_find(_evas_gl_visuals, &idx);
1297    if (!evis)
1298      {
1299         eng_best_visual_get(einfo);
1300         evis = eina_hash_find(_evas_gl_visuals, &idx);
1301         if (!evis) return 0;
1302      }
1303    return evis->cmap;
1304 }
1305 
1306 int
eng_best_depth_get(Evas_Engine_Info_GL_X11 * einfo)1307 eng_best_depth_get(Evas_Engine_Info_GL_X11 *einfo)
1308 {
1309    Evas_GL_X11_Visual *evis;
1310    int idx;
1311 
1312    if (!einfo) return 0;
1313    if (!einfo->info.display) return 0;
1314    idx = _visuals_hash_index_get_from_info(einfo);
1315    evis = eina_hash_find(_evas_gl_visuals, &idx);
1316    if (!evis)
1317      {
1318         eng_best_visual_get(einfo);
1319         evis = eina_hash_find(_evas_gl_visuals, &idx);
1320         if (!evis) return 0;
1321      }
1322    return evis->info.depth;
1323 }
1324 
1325 Context_3D *
eng_gl_context_new(Outbuf * win)1326 eng_gl_context_new(Outbuf *win)
1327 {
1328    Context_3D *ctx;
1329 #if GL_GLES
1330    int context_attrs[3] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
1331 #endif
1332 
1333    if (!win) return NULL;
1334 
1335    ctx = calloc(1, sizeof(Context_3D));
1336    if (!ctx) return NULL;
1337 
1338 #if GL_GLES
1339    if (gles3_supported)
1340      context_attrs[1] = 3;
1341    ctx->context = eglCreateContext(win->egl_disp, win->egl_config,
1342                                    win->egl_context, context_attrs);
1343 
1344    if (!ctx->context)
1345      {
1346         ERR("EGL context creation failed.");
1347         goto error;
1348      }
1349 
1350    ctx->display = win->egl_disp;
1351    ctx->surface = win->egl_surface;
1352 #else
1353    ctx->context = glXCreateContext(win->disp, win->visualinfo, win->context, 1);
1354 
1355    if (!ctx->context)
1356      {
1357         ERR("GLX context creation failed.");
1358         goto error;
1359      }
1360 
1361    ctx->display = win->disp;
1362    ctx->glxwin = win->glxwin;
1363    ctx->win = win->win;
1364 #endif
1365 
1366    return ctx;
1367 
1368 error:
1369    free(ctx);
1370    return NULL;
1371 }
1372 
1373 void
eng_gl_context_free(Context_3D * ctx)1374 eng_gl_context_free(Context_3D *ctx)
1375 {
1376 #if GL_GLES
1377    eglDestroyContext(ctx->display, ctx->context);
1378 #else
1379    glXDestroyContext(ctx->display, ctx->context);
1380 #endif
1381 
1382    free(ctx);
1383 }
1384 
1385 void
eng_gl_context_use(Context_3D * ctx)1386 eng_gl_context_use(Context_3D *ctx)
1387 {
1388 #if GL_GLES
1389     SET_RESTORE_CONTEXT();
1390    if (evas_eglMakeCurrent(ctx->display, ctx->surface,
1391                       ctx->surface, ctx->context) == EGL_FALSE)
1392      {
1393         ERR("evas_eglMakeCurrent() failed.");
1394      }
1395 #else
1396    if (!__glXMakeContextCurrent(ctx->display, ctx->glxwin, ctx->context))
1397      {
1398         ERR("glXMakeContextCurrent(%p, %p, %p, %p) failed.",
1399             (void *)ctx->display, (void *)ctx->glxwin,
1400             (void *)ctx->win, (void *)ctx->context);
1401      }
1402 #endif
1403 }
1404 
1405 void
eng_outbuf_reconfigure(Outbuf * ob,int w,int h,int rot,Outbuf_Depth depth EINA_UNUSED)1406 eng_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth EINA_UNUSED)
1407 {
1408    ob->w = w;
1409    ob->h = h;
1410    ob->rot = rot;
1411    eng_window_use(ob);
1412    glsym_evas_gl_common_context_resize(ob->gl_context, w, h, rot);
1413 }
1414 
1415 int
eng_outbuf_get_rot(Outbuf * ob)1416 eng_outbuf_get_rot(Outbuf *ob)
1417 {
1418    return ob->rot;
1419 }
1420 
1421 Render_Output_Swap_Mode
eng_outbuf_swap_mode(Outbuf * ob)1422 eng_outbuf_swap_mode(Outbuf *ob)
1423 {
1424    if (ob->swap_mode == MODE_AUTO && extn_have_buffer_age)
1425      {
1426         Render_Output_Swap_Mode swap_mode;
1427         eina_evlog("+gl_query_surf_swap_mode", ob, 0.0, NULL);
1428         measure(0, "query age");
1429 #ifdef GL_GLES
1430         EGLint age = 0;
1431 
1432         if (!eglQuerySurface(ob->egl_disp, ob->egl_surface,
1433                              EGL_BUFFER_AGE_EXT, &age))
1434           age = 0;
1435 #else
1436         unsigned int age = 0;
1437 
1438         if (glsym_glXQueryDrawable)
1439           glsym_glXQueryDrawable(ob->disp, ob->glxwin,
1440                                  GLX_BACK_BUFFER_AGE_EXT, &age);
1441 #endif
1442         measure(1, "query age");
1443         if (age == 1) swap_mode = MODE_COPY;
1444         else if (age == 2) swap_mode = MODE_DOUBLE;
1445         else if (age == 3) swap_mode = MODE_TRIPLE;
1446         else if (age == 4) swap_mode = MODE_QUADRUPLE;
1447         else swap_mode = MODE_FULL;
1448         if ((int)age != ob->prev_age)
1449           {
1450              char buf[16];
1451              snprintf(buf, sizeof(buf), "! %i", (int)age);
1452              eina_evlog("!gl_buffer_age", ob, 0.0, buf);
1453              swap_mode = MODE_FULL;
1454           }
1455         else
1456           {
1457              char buf[16];
1458              snprintf(buf, sizeof(buf), "%i", (int)age);
1459              eina_evlog("!gl_buffer_age", ob, 0.0, buf);
1460           }
1461         ob->prev_age = age;
1462 
1463         eina_evlog("-gl_query_surf_swap_mode", ob, 0.0, NULL);
1464         return swap_mode;
1465      }
1466 
1467    return ob->swap_mode;
1468 }
1469 
1470 Eina_Bool
eng_outbuf_region_first_rect(Outbuf * ob)1471 eng_outbuf_region_first_rect(Outbuf *ob)
1472 {
1473    ob->gl_context->preserve_bit = GL_COLOR_BUFFER_BIT0_QCOM;
1474 
1475    glsym_evas_gl_preload_render_lock(eng_preload_make_current, ob);
1476 #ifdef GL_GLES
1477    // dont need to for egl - eng_window_use() can check for other ctxt's
1478 #else
1479    eng_window_use(NULL);
1480 #endif
1481    eng_window_use(ob);
1482    if (!_re_wincheck(ob)) return EINA_TRUE;
1483 
1484    glsym_evas_gl_common_context_resize(ob->gl_context,
1485                                  ob->w, ob->h,
1486                                  ob->rot);
1487 
1488    glsym_evas_gl_common_context_flush(ob->gl_context);
1489    glsym_evas_gl_common_context_newframe(ob->gl_context);
1490    if (partial_render_debug == 1)
1491      {
1492         glClearColor(0.2, 0.5, 1.0, 1.0);
1493         glClear(GL_COLOR_BUFFER_BIT);
1494      }
1495 
1496    return EINA_FALSE;
1497 }
1498 
1499 #ifdef GL_GLES
1500 static void
_convert_to_glcoords(int * result,Outbuf * ob,int x,int y,int w,int h)1501 _convert_to_glcoords(int *result, Outbuf *ob, int x, int y, int w, int h)
1502 {
1503 
1504    switch (ob->rot)
1505      {
1506       case 0:
1507         result[0] = x;
1508         result[1] = ob->gl_context->h - (y + h);
1509         result[2] = w;
1510         result[3] = h;
1511         break;
1512       case 90:
1513         result[0] = y;
1514         result[1] = x;
1515         result[2] = h;
1516         result[3] = w;
1517         break;
1518       case 180:
1519         result[0] = ob->gl_context->w - (x + w);
1520         result[1] = y;
1521         result[2] = w;
1522         result[3] = h;
1523         break;
1524       case 270:
1525         result[0] = ob->gl_context->h - (y + h);
1526         result[1] = ob->gl_context->w - (x + w);
1527         result[2] = h;
1528         result[3] = w;
1529         break;
1530       default:
1531         result[0] = x;
1532         result[1] = ob->gl_context->h - (y + h);
1533         result[2] = w;
1534         result[3] = h;
1535         break;
1536      }
1537 }
1538 
1539 void
eng_outbuf_damage_region_set(Outbuf * ob,Tilebuf_Rect * damage)1540 eng_outbuf_damage_region_set(Outbuf *ob, Tilebuf_Rect *damage)
1541 {
1542    if (glsym_eglSetDamageRegionKHR)
1543      {
1544         Tilebuf_Rect *tr;
1545         int *rect, *rects, count;
1546 
1547         count = eina_inlist_count(EINA_INLIST_GET(damage));
1548         rects = alloca(sizeof(int) * 4 * count);
1549         rect = rects;
1550         EINA_INLIST_FOREACH(damage, tr)
1551           {
1552              _convert_to_glcoords(rect, ob, tr->x, tr->y, tr->w, tr->h);
1553              rect += 4;
1554           }
1555         glsym_eglSetDamageRegionKHR(ob->egl_disp, ob->egl_surface, rects, count);
1556      }
1557 }
1558 #endif
1559 
1560 void*
eng_outbuf_new_region_for_update(Outbuf * ob,int x,int y,int w,int h,int * cx EINA_UNUSED,int * cy EINA_UNUSED,int * cw EINA_UNUSED,int * ch EINA_UNUSED)1561 eng_outbuf_new_region_for_update(Outbuf *ob,
1562                                  int x, int y, int w, int h,
1563                                  int *cx EINA_UNUSED, int *cy EINA_UNUSED,
1564                                  int *cw EINA_UNUSED, int *ch EINA_UNUSED)
1565 {
1566    if (w == (int) ob->w && h == (int) ob->h)
1567      {
1568         ob->gl_context->master_clip.enabled = EINA_FALSE;
1569      }
1570    else
1571      {
1572         ob->gl_context->master_clip.enabled = EINA_TRUE;
1573         ob->gl_context->master_clip.x = x;
1574         ob->gl_context->master_clip.y = y;
1575         ob->gl_context->master_clip.w = w;
1576         ob->gl_context->master_clip.h = h;
1577      }
1578    return ob->gl_context->def_surface;
1579 }
1580 
1581 void
eng_outbuf_push_updated_region(Outbuf * ob,RGBA_Image * update EINA_UNUSED,int x EINA_UNUSED,int y EINA_UNUSED,int w EINA_UNUSED,int h EINA_UNUSED)1582 eng_outbuf_push_updated_region(Outbuf *ob, RGBA_Image *update EINA_UNUSED,
1583                                int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
1584 {
1585    /* Is it really necessary to flush per region ? Shouldn't we be able to
1586       still do that for the full canvas when doing partial update */
1587    if (!_re_wincheck(ob)) return;
1588    ob->draw.drew = 1;
1589    glsym_evas_gl_common_context_flush(ob->gl_context);
1590 }
1591 
1592 void
eng_outbuf_flush(Outbuf * ob,Tilebuf_Rect * surface_damage EINA_UNUSED,Tilebuf_Rect * buffer_damage,Evas_Render_Mode render_mode)1593 eng_outbuf_flush(Outbuf *ob, Tilebuf_Rect *surface_damage EINA_UNUSED, Tilebuf_Rect *buffer_damage, Evas_Render_Mode render_mode)
1594 {
1595    Tilebuf_Rect *rects = buffer_damage;
1596 
1597    if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) goto end;
1598 
1599    if (!_re_wincheck(ob)) goto end;
1600    if (!ob->draw.drew) goto end;
1601 
1602    ob->draw.drew = 0;
1603    eng_window_use(ob);
1604    glsym_evas_gl_common_context_done(ob->gl_context);
1605 
1606    // Save contents of the framebuffer to a file
1607    if (swap_buffer_debug_mode == 1)
1608      {
1609         if (swap_buffer_debug)
1610           {
1611              char fname[100];
1612              int ret = 0;
1613              snprintf(fname, sizeof(fname), "%p", (void*)ob);
1614 
1615              ret = glsym_evas_gl_common_buffer_dump(ob->gl_context,
1616                                                     (const char*)debug_dir,
1617                                                     (const char*)fname,
1618                                                     ob->frame_cnt,
1619                                                     NULL);
1620              if (!ret) swap_buffer_debug_mode = 0;
1621           }
1622      }
1623 
1624 #ifdef GL_GLES
1625    if (!ob->vsync)
1626      {
1627         if (ob->info->vsync) eglSwapInterval(ob->egl_disp, 1);
1628         else eglSwapInterval(ob->egl_disp, 0);
1629         ob->vsync = 1;
1630      }
1631    if ((glsym_eglSwapBuffersWithDamage) && (rects) &&
1632        (ob->swap_mode != MODE_FULL))
1633      {
1634         EGLint num = 0, *result = NULL, i = 0;
1635         Tilebuf_Rect *r;
1636 
1637         // if partial swaps can be done use re->rects
1638         num = eina_inlist_count(EINA_INLIST_GET(rects));
1639         if (num > 0)
1640           {
1641              result = alloca(sizeof(EGLint) * 4 * num);
1642              EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
1643                {
1644                   _convert_to_glcoords(&result[i], ob, r->x, r->y, r->w, r->h);
1645                   i += 4;
1646                }
1647              measure(0, "swap with damage");
1648              glsym_eglSwapBuffersWithDamage(ob->egl_disp,
1649                                             ob->egl_surface,
1650                                             result, num);
1651              measure(1, "swap with damage");
1652           }
1653      }
1654    else
1655      {
1656         measure(0, "swap");
1657         eglSwapBuffers(ob->egl_disp, ob->egl_surface);
1658         measure(1, "swap");
1659      }
1660 
1661 //xx   if (!safe_native) eglWaitGL();
1662 //   if (eglGetError() != EGL_SUCCESS)
1663 //     {
1664 //        printf("Error:  eglSwapBuffers() fail.\n");
1665 //     }
1666 #else
1667    (void)rects;
1668 #ifdef VSYNC_TO_SCREEN
1669    if (ob->info->vsync)
1670      {
1671         if (glsym_glXSwapIntervalEXT)
1672           {
1673              if (!ob->vsync)
1674                {
1675                   if (ob->info->vsync) glsym_glXSwapIntervalEXT(ob->disp, ob->win, 1);
1676                   else glsym_glXSwapIntervalEXT(ob->disp, ob->win, 0);
1677                   ob->vsync = 1;
1678                }
1679           }
1680         else if (glsym_glXSwapIntervalSGI)
1681           {
1682              if (!ob->vsync)
1683                {
1684                   if (ob->info->vsync) glsym_glXSwapIntervalSGI(1);
1685                   else glsym_glXSwapIntervalSGI(0);
1686                   ob->vsync = 1;
1687                }
1688           }
1689         else
1690           {
1691              if ((glsym_glXGetVideoSync) && (glsym_glXWaitVideoSync))
1692                {
1693                   unsigned int rc;
1694 
1695                   glsym_glXGetVideoSync(&rc);
1696                   glsym_glXWaitVideoSync(1, 0, &rc);
1697                }
1698           }
1699      }
1700 #endif
1701    // XXX: if partial swaps can be done use re->rects
1702    measure(0, "swap");
1703    glXSwapBuffers(ob->disp, ob->glxwin);
1704    measure(1, "swap");
1705 #endif
1706    // clear out rects after swap as we may use them during swap
1707 
1708    ob->frame_cnt++;
1709 
1710  end:
1711    glsym_evas_gl_preload_render_unlock(eng_preload_make_current, ob);
1712 }
1713 
1714 Evas_Engine_GL_Context *
eng_outbuf_gl_context_get(Outbuf * ob)1715 eng_outbuf_gl_context_get(Outbuf *ob)
1716 {
1717    return ob->gl_context;
1718 }
1719 
1720 void *
eng_outbuf_egl_display_get(Outbuf * ob)1721 eng_outbuf_egl_display_get(Outbuf *ob)
1722 {
1723 #ifdef GL_GLES
1724    return ob->egl_disp;
1725 #else
1726    (void) ob;
1727    return NULL;
1728 #endif
1729 }
1730