#include "evas_common_private.h" /* Also includes international specific stuff */ #include "evas_engine.h" #include "../gl_common/evas_gl_define.h" #include "../software_generic/evas_native_common.h" #ifdef HAVE_DLSYM # include /* dlopen,dlclose,etc */ #else # error gl_x11 should not get compiled if dlsym is not found on the system! #endif #define EVAS_GL_NO_GL_H_CHECK 1 #include "Evas_GL.h" #define EVAS_GL_UPDATE_TILE_SIZE 16 typedef struct _Render_Engine Render_Engine; struct _Render_Engine { Render_Output_GL_Generic generic; }; const char *debug_dir; int swap_buffer_debug_mode = -1; int swap_buffer_debug = 0; int partial_render_debug = -1; int extn_have_buffer_age = 1; static int initted = 0; static int gl_wins = 0; #ifdef GL_GLES static int extn_have_y_inverted = 1; #endif typedef void (*_eng_fn) (void); typedef _eng_fn (*glsym_func_eng_fn) (); typedef void (*glsym_func_void) (); typedef void *(*glsym_func_void_ptr) (); typedef int (*glsym_func_int) (); typedef unsigned int (*glsym_func_uint) (); typedef const char *(*glsym_func_const_char_ptr) (); Evas_GL_Common_Image_Call glsym_evas_gl_common_image_ref = NULL; Evas_GL_Common_Image_Call glsym_evas_gl_common_image_unref = NULL; Evas_GL_Common_Image_Call glsym_evas_gl_common_image_free = NULL; Evas_GL_Common_Image_Call glsym_evas_gl_common_image_native_disable = NULL; Evas_GL_Common_Image_Call glsym_evas_gl_common_image_native_enable = NULL; Evas_GL_Common_Image_New_From_Data glsym_evas_gl_common_image_new_from_data = NULL; Evas_GL_Common_Context_Call glsym_evas_gl_common_image_all_unload = NULL; Evas_GL_Preload glsym_evas_gl_preload_init = NULL; Evas_GL_Preload glsym_evas_gl_preload_shutdown = NULL; EVGL_Engine_Call glsym_evgl_engine_shutdown = NULL; EVGL_Native_Surface_Call glsym_evgl_native_surface_buffer_get = NULL; EVGL_Native_Surface_Yinvert_Call glsym_evgl_native_surface_yinvert_get = NULL; EVGL_Current_Native_Context_Get_Call glsym_evgl_current_native_context_get = NULL; Evas_Gl_Symbols glsym_evas_gl_symbols = NULL; Evas_GL_Common_Context_New glsym_evas_gl_common_context_new = NULL; Evas_GL_Common_Context_Call glsym_evas_gl_common_context_flush = NULL; Evas_GL_Common_Context_Call glsym_evas_gl_common_context_free = NULL; Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use = NULL; Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe = NULL; Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done = NULL; Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize = NULL; Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump = NULL; Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock = NULL; Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock = NULL; Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_relax = NULL; glsym_func_void glsym_evas_gl_common_shaders_flush = NULL; glsym_func_void glsym_evas_gl_common_error_set = NULL; glsym_func_int glsym_evas_gl_common_error_get = NULL; glsym_func_void_ptr glsym_evas_gl_common_current_context_get = NULL; #ifdef GL_GLES _eng_fn (*glsym_eglGetProcAddress) (const char *a) = NULL; EGLImageKHR (*glsym_evas_gl_common_eglCreateImage)(EGLDisplay a, EGLContext b, EGLenum c, EGLClientBuffer d, const EGLAttrib *e) = NULL; int (*glsym_evas_gl_common_eglDestroyImage) (EGLDisplay a, void *b) = NULL; void (*glsym_glEGLImageTargetTexture2DOES) (int a, void *b) = NULL; unsigned int (*glsym_eglSwapBuffersWithDamage) (EGLDisplay a, void *b, const EGLint *d, EGLint c) = NULL; unsigned int (*glsym_eglSetDamageRegionKHR) (EGLDisplay a, EGLSurface b, EGLint *c, EGLint d) = NULL; unsigned int (*glsym_eglQueryWaylandBufferWL)(EGLDisplay a, /*struct wl_resource */void *b, EGLint c, EGLint *d) = NULL; #else typedef XID (*glsym_func_xid) (); _eng_fn (*glsym_glXGetProcAddress) (const char *a) = NULL; void (*glsym_glXBindTexImage) (Display *a, GLXDrawable b, int c, int *d) = NULL; void (*glsym_glXReleaseTexImage) (Display *a, GLXDrawable b, int c) = NULL; int (*glsym_glXGetVideoSync) (unsigned int *a) = NULL; int (*glsym_glXWaitVideoSync) (int a, int b, unsigned int *c) = NULL; XID (*glsym_glXCreatePixmap) (Display *a, void *b, Pixmap c, const int *d) = NULL; void (*glsym_glXDestroyPixmap) (Display *a, XID b) = NULL; void (*glsym_glXQueryDrawable) (Display *a, XID b, int c, unsigned int *d) = NULL; int (*glsym_glXSwapIntervalSGI) (int a) = NULL; void (*glsym_glXSwapIntervalEXT) (Display *s, GLXDrawable b, int c) = NULL; void (*glsym_glXReleaseBuffersMESA) (Display *a, XID b) = NULL; #endif static inline Outbuf * eng_get_ob(Render_Engine *re) { return re->generic.software.ob; } //----------------------------------------------------------// // NEW_EVAS_GL Engine Functions static void * evgl_eng_display_get(void *data) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, NULL); */ if (!re) { ERR("Invalid Render Engine Data!"); return NULL; } #ifdef GL_GLES if (eng_get_ob(re)) return (void*)eng_get_ob(re)->egl_disp; #else if (eng_get_ob(re)->info) return (void*)eng_get_ob(re)->info->info.display; #endif else return NULL; } static void * evgl_eng_evas_surface_get(void *data) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, NULL); */ if (!re) { ERR("Invalid Render Engine Data!"); return NULL; } #ifdef GL_GLES if (eng_get_ob(re)) return (void*)eng_get_ob(re)->egl_surface; #else if (eng_get_ob(re)) return (void*)eng_get_ob(re)->win; #endif else return NULL; } #ifdef GL_GLES static EGLDisplay main_dpy = EGL_NO_DISPLAY; static EGLSurface main_draw = EGL_NO_SURFACE; static EGLSurface main_read = EGL_NO_SURFACE; static EGLContext main_ctx = EGL_NO_CONTEXT; EGLContext evas_eglGetCurrentContext(void) { if (eina_main_loop_is()) return main_ctx; else return eglGetCurrentContext(); } EGLSurface evas_eglGetCurrentSurface(EGLint readdraw) { if (eina_main_loop_is()) return (readdraw == EGL_READ) ? main_read : main_draw; else return eglGetCurrentSurface(readdraw); } EGLDisplay evas_eglGetCurrentDisplay(void) { if (eina_main_loop_is()) return main_dpy; else return eglGetCurrentDisplay(); } EGLBoolean evas_eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { if (eina_main_loop_is()) { EGLBoolean ret; if ((dpy == main_dpy) && (draw == main_draw) && (read == main_read) && (ctx == main_ctx)) return 1; ret = eglMakeCurrent(dpy, draw, read, ctx); if (ret) { main_dpy = dpy; main_draw = draw; main_read = read; main_ctx = ctx; } return ret; } else return eglMakeCurrent(dpy, draw, read, ctx); } #endif static int evgl_eng_make_current(void *data, void *surface, void *context, int flush) { Render_Engine *re = (Render_Engine *)data; int ret = 0; /* EVGLINIT(re, 0); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return 0; } #ifdef GL_GLES EGLContext ctx = (EGLContext)context; EGLSurface sfc = (EGLSurface)surface; EGLDisplay dpy = eng_get_ob(re)->egl_disp; //eglGetCurrentDisplay(); if ((!context) && (!surface)) { ret = evas_eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!ret) { int err = eglGetError(); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); ERR("evas_eglMakeCurrent() failed! Error Code=%#x", err); return 0; } return 1; } // FIXME: Check (eglGetCurrentDisplay() != dpy) ? if ((evas_eglGetCurrentContext() != ctx) || (evas_eglGetCurrentSurface(EGL_READ) != sfc) || (evas_eglGetCurrentSurface(EGL_DRAW) != sfc) ) { //!!!! Does it need to be flushed with it's set to NULL above?? // Flush remainder of what's in Evas' pipeline if (flush) eng_window_use(NULL); // Do a make current ret = evas_eglMakeCurrent(dpy, sfc, sfc, ctx); if (!ret) { int err = eglGetError(); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); ERR("evas_eglMakeCurrent() failed! Error Code=%#x", err); return 0; } } return 1; #else GLXContext ctx = (GLXContext)context; Window sfc = (Window)surface; if ((!context) && (!surface)) { ret = __glXMakeContextCurrent(eng_get_ob(re)->info->info.display, 0, NULL); if (!ret) { ERR("glXMakeContextCurrent() failed!"); glsym_evas_gl_common_error_set(EVAS_GL_BAD_DISPLAY); return 0; } return 1; } if ((glXGetCurrentContext() != ctx)) { //!!!! Does it need to be flushed with it's set to NULL above?? // Flush remainder of what's in Evas' pipeline if (flush) eng_window_use(NULL); // Do a make current if ((sfc == eng_get_ob(re)->win) || (sfc == eng_get_ob(re)->glxwin)) ret = __glXMakeContextCurrent(eng_get_ob(re)->info->info.display, eng_get_ob(re)->glxwin, ctx); else ret = __glXMakeContextCurrent(eng_get_ob(re)->info->info.display, sfc, ctx); if (!ret) { ERR("glXMakeContextCurrent() failed. Ret: %d! Context: %p Surface: %p", ret, (void *)ctx, (void *)sfc); glsym_evas_gl_common_error_set(EVAS_GL_BAD_DISPLAY); return 0; } } return 1; #endif } static void * evgl_eng_native_window_create(void *data) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, NULL); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return NULL; } XSetWindowAttributes attr; Window win; attr.backing_store = NotUseful; attr.override_redirect = True; attr.border_pixel = 0; attr.background_pixmap = None; attr.bit_gravity = NorthWestGravity; attr.win_gravity = NorthWestGravity; attr.save_under = False; attr.do_not_propagate_mask = NoEventMask; attr.event_mask = 0; win = XCreateWindow(eng_get_ob(re)->info->info.display, eng_get_ob(re)->win, -20, -20, 2, 2, 0, CopyFromParent, InputOutput, CopyFromParent, CWBackingStore | CWOverrideRedirect | CWBorderPixel | CWBackPixmap | CWSaveUnder | CWDontPropagate | CWEventMask | CWBitGravity | CWWinGravity, &attr); if (!win) { ERR("Creating native X window failed."); glsym_evas_gl_common_error_set(EVAS_GL_BAD_DISPLAY); return NULL; } return (void*)win; } static int evgl_eng_native_window_destroy(void *data, void *native_window) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, 0); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return 0; } if (!native_window) { ERR("Inavlid native surface."); glsym_evas_gl_common_error_set(EVAS_GL_BAD_NATIVE_WINDOW); return 0; } XDestroyWindow(eng_get_ob(re)->info->info.display, (Window)native_window); native_window = NULL; return 1; } // Theoretically, we wouldn't need this functoin if the surfaceless context // is supported. But, until then... static void * evgl_eng_window_surface_create(void *data, void *native_window EINA_UNUSED) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, NULL); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return NULL; } #ifdef GL_GLES EGLSurface surface = EGL_NO_SURFACE; // Create resource surface for EGL surface = eglCreateWindowSurface(eng_get_ob(re)->egl_disp, eng_get_ob(re)->egl_config, (EGLNativeWindowType)native_window, NULL); if (!surface) { ERR("Creating window surface failed. Error: %#x.", eglGetError()); abort(); return NULL; } return (void*)surface; #else /* // We don't need to create new one for GLX Window surface; surface = eng_get_ob(re)->win; return (void *)surface; */ return (void *)native_window; #endif } static int evgl_eng_window_surface_destroy(void *data, void *surface) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, 0); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return 0; } #ifdef GL_GLES if (!surface) { ERR("Invalid surface."); glsym_evas_gl_common_error_set(EVAS_GL_BAD_SURFACE); return 0; } eglDestroySurface(eng_get_ob(re)->egl_disp, (EGLSurface)surface); #endif return 1; if (surface) return 0; } static void * evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version version) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, NULL); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return NULL; } if ((version < EVAS_GL_GLES_1_X) || (version > EVAS_GL_GLES_3_X)) { ERR("Invalid context version number %d", version); glsym_evas_gl_common_error_set(EVAS_GL_BAD_PARAMETER); return NULL; } #ifdef GL_GLES if ((version == EVAS_GL_GLES_3_X) && ((!eng_get_ob(re)->gl_context) || (eng_get_ob(re)->gl_context->gles_version != EVAS_GL_GLES_3_X))) { ERR("GLES 3 version not supported!"); glsym_evas_gl_common_error_set(EVAS_GL_BAD_ATTRIBUTE); return NULL; } EGLContext context = EGL_NO_CONTEXT; int context_attrs[3]; /* Upgrade GLES 2 to GLES 3. * * FIXME: Maybe we don't want to do this, unless we have no choice. * An alternative would be to use eglCreateImage() to share the indirect * rendering FBO between two contexts of incompatible version. For now, * we always upgrade the real context version to GLES 3 when it's available. * But this leads to some issues, namely that the list of extensions is * different, and MSAA surfaces also work differently. */ if (gles3_supported && (version >= EVAS_GL_GLES_2_X)) version = 3; context_attrs[0] = EGL_CONTEXT_CLIENT_VERSION; context_attrs[1] = version; context_attrs[2] = EGL_NONE; // Share context already assumes that it's sharing with evas' context if (share_ctx) { context = eglCreateContext(eng_get_ob(re)->egl_disp, eng_get_ob(re)->egl_config, (EGLContext)share_ctx, context_attrs); } else if ((version == EVAS_GL_GLES_1_X) || (version == EVAS_GL_GLES_3_X)) { context = eglCreateContext(eng_get_ob(re)->egl_disp, eng_get_ob(re)->egl_config, NULL, context_attrs); } else { context = eglCreateContext(eng_get_ob(re)->egl_disp, eng_get_ob(re)->egl_config, eng_get_ob(re)->egl_context, // Evas' GL Context context_attrs); } if (!context) { int err = eglGetError(); ERR("Engine Context Creations Failed. Error: %#x.", err); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); return NULL; } return (void*)context; #else GLXContext context = NULL; // Share context already assumes that it's sharing with evas' context if (share_ctx) { context = glXCreateContext(eng_get_ob(re)->info->info.display, eng_get_ob(re)->visualinfo, (GLXContext)share_ctx, 1); } else { context = glXCreateContext(eng_get_ob(re)->info->info.display, eng_get_ob(re)->visualinfo, eng_get_ob(re)->context, // Evas' GL Context 1); } if (!context) { ERR("Internal Resource Context Creations Failed."); if(!(eng_get_ob(re)->info->info.display)) glsym_evas_gl_common_error_set(EVAS_GL_BAD_DISPLAY); if(!(eng_get_ob(re)->win)) glsym_evas_gl_common_error_set(EVAS_GL_BAD_NATIVE_WINDOW); return NULL; } return (void*)context; #endif } static int evgl_eng_context_destroy(void *data, void *context) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, 0); */ if ((!re) || (!context)) { ERR("Invalid Render Input Data. Engine: %p, Context: %p", data, context); if (!re) glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); if (!context) glsym_evas_gl_common_error_set(EVAS_GL_BAD_CONTEXT); return 0; } #ifdef GL_GLES eglDestroyContext(eng_get_ob(re)->egl_disp, (EGLContext)context); #else glXDestroyContext(eng_get_ob(re)->info->info.display, (GLXContext)context); #endif return 1; } static const char * evgl_eng_string_get(void *data) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, NULL); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return NULL; } #ifdef GL_GLES return eglQueryString(eng_get_ob(re)->egl_disp, EGL_EXTENSIONS); #else return glXQueryExtensionsString(eng_get_ob(re)->info->info.display, eng_get_ob(re)->info->info.screen); #endif } static void * evgl_eng_proc_address_get(const char *name) { #ifdef GL_GLES if (glsym_eglGetProcAddress) return glsym_eglGetProcAddress(name); return dlsym(RTLD_DEFAULT, name); #else if (glsym_glXGetProcAddress) return glsym_glXGetProcAddress(name); return dlsym(RTLD_DEFAULT, name); #endif } static int evgl_eng_rotation_angle_get(void *data) { Render_Engine *re = (Render_Engine *)data; /* EVGLINIT(re, 0); */ if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return 0; } if ((eng_get_ob(re)) && (eng_get_ob(re)->gl_context)) return eng_get_ob(re)->gl_context->rot; else { ERR("Unable to retrieve rotation angle."); glsym_evas_gl_common_error_set(EVAS_GL_BAD_CONTEXT); return 0; } } static void * evgl_eng_pbuffer_surface_create(void *data, EVGL_Surface *sfc, const int *attrib_list) { Render_Output_GL_Generic *re = data; // TODO: Add support for surfaceless pbuffers (EGL_NO_TEXTURE) // TODO: Add support for EGL_MIPMAP_TEXTURE??? (GLX doesn't support them) if (attrib_list) WRN("This PBuffer implementation does not support extra attributes yet"); #ifdef GL_GLES Evas_Engine_GL_Context *evasglctx; int config_attrs[20]; int surface_attrs[20]; EGLSurface egl_sfc; EGLConfig egl_cfg; int num_config, i = 0; EGLDisplay disp; EGLContext ctx; disp = re->window_egl_display_get(re->software.ob); evasglctx = re->window_gl_context_get(re->software.ob); ctx = evasglctx->eglctxt; #if 0 // Choose framebuffer configuration // DISABLED FOR NOW if (sfc->pbuffer.color_fmt != EVAS_GL_NO_FBO) { config_attrs[i++] = EGL_RED_SIZE; config_attrs[i++] = 1; config_attrs[i++] = EGL_GREEN_SIZE; config_attrs[i++] = 1; config_attrs[i++] = EGL_BLUE_SIZE; config_attrs[i++] = 1; if (sfc->pbuffer.color_fmt == EVAS_GL_RGBA_8888) { config_attrs[i++] = EGL_ALPHA_SIZE; config_attrs[i++] = 1; //config_attrs[i++] = EGL_BIND_TO_TEXTURE_RGBA; //config_attrs[i++] = EGL_TRUE; } else { //config_attrs[i++] = EGL_BIND_TO_TEXTURE_RGB; //config_attrs[i++] = EGL_TRUE; } } if (sfc->depth_fmt || sfc->depth_stencil_fmt) { config_attrs[i++] = EGL_DEPTH_SIZE; config_attrs[i++] = 1; } if (sfc->stencil_fmt || sfc->depth_stencil_fmt) { config_attrs[i++] = EGL_STENCIL_SIZE; config_attrs[i++] = 1; } config_attrs[i++] = EGL_RENDERABLE_TYPE; if (gles3_supported) config_attrs[i++] = EGL_OPENGL_ES3_BIT_KHR; else config_attrs[i++] = EGL_OPENGL_ES2_BIT; config_attrs[i++] = EGL_SURFACE_TYPE; config_attrs[i++] = EGL_PBUFFER_BIT; config_attrs[i++] = EGL_NONE; #else // It looks like evas_eglMakeCurrent might fail if we use a different config from // the actual display surface. This is weird. i = 0; config_attrs[i++] = EGL_CONFIG_ID; config_attrs[i++] = 0; config_attrs[i++] = EGL_NONE; eglQueryContext(disp, ctx, EGL_CONFIG_ID, &config_attrs[1]); #endif if (!eglChooseConfig(disp, config_attrs, &egl_cfg, 1, &num_config) || (num_config < 1)) { int err = eglGetError(); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); ERR("eglChooseConfig failed with error %x", err); return NULL; } // Now, choose the config for the PBuffer i = 0; surface_attrs[i++] = EGL_WIDTH; surface_attrs[i++] = sfc->w; surface_attrs[i++] = EGL_HEIGHT; surface_attrs[i++] = sfc->h; #if 0 // Adding these parameters will trigger EGL_BAD_ATTRIBUTE because // the config also requires EGL_BIND_TO_TEXTURE_RGB[A]. But some drivers // don't support those configs (eg. nvidia) surface_attrs[i++] = EGL_TEXTURE_FORMAT; if (sfc->pbuffer.color_fmt == EVAS_GL_RGB_888) surface_attrs[i++] = EGL_TEXTURE_RGB; else surface_attrs[i++] = EGL_TEXTURE_RGBA; surface_attrs[i++] = EGL_TEXTURE_TARGET; surface_attrs[i++] = EGL_TEXTURE_2D; surface_attrs[i++] = EGL_MIPMAP_TEXTURE; surface_attrs[i++] = EINA_TRUE; #endif surface_attrs[i++] = EGL_NONE; egl_sfc = eglCreatePbufferSurface(disp, egl_cfg, surface_attrs); if (!egl_sfc) { int err = eglGetError(); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); ERR("eglCreatePbufferSurface failed with error %x", err); return NULL; } return egl_sfc; #else Evas_Engine_GL_Context *evasglctx; GLXPbuffer pbuf; GLXFBConfig *cfgs; int config_attrs[20]; int surface_attrs[20]; int ncfg = 0, i; evasglctx = re->window_gl_context_get(re->software.ob); #ifndef GLX_VISUAL_ID # define GLX_VISUAL_ID 0x800b #endif i = 0; #if 0 // DISABLED BECAUSE BadMatch HAPPENS if (sfc->pbuffer.color_fmt != EVAS_GL_NO_FBO) { config_attrs[i++] = GLX_BUFFER_SIZE; if (sfc->pbuffer.color_fmt == EVAS_GL_RGBA_8888) { config_attrs[i++] = 32; //config_attrs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT; //config_attrs[i++] = 1; } else { config_attrs[i++] = 24; //config_attrs[i++] = GLX_BIND_TO_TEXTURE_RGB_EXT; //config_attrs[i++] = 1; } } if (sfc->depth_fmt) { config_attrs[i++] = GLX_DEPTH_SIZE; config_attrs[i++] = 24; // FIXME: This should depend on the requested bits } if (sfc->stencil_fmt) { config_attrs[i++] = GLX_STENCIL_SIZE; config_attrs[i++] = 8; // FIXME: This should depend on the requested bits } //config_attrs[i++] = GLX_VISUAL_ID; //config_attrs[i++] = XVisualIDFromVisual(vis); #else config_attrs[i++] = GLX_FBCONFIG_ID; if (sfc->pbuffer.color_fmt == EVAS_GL_RGB_888) config_attrs[i++] = evasglctx->glxcfg_rgb; else config_attrs[i++] = evasglctx->glxcfg_rgba; #endif config_attrs[i++] = 0; cfgs = glXChooseFBConfig(re->software.ob->disp, re->software.ob->screen, config_attrs, &ncfg); if (!cfgs || !ncfg) { ERR("GLX failed to find a valid config for the pbuffer"); if (cfgs) XFree(cfgs); return NULL; } i = 0; surface_attrs[i++] = GLX_LARGEST_PBUFFER; surface_attrs[i++] = 0; surface_attrs[i++] = GLX_PBUFFER_WIDTH; surface_attrs[i++] = sfc->w; surface_attrs[i++] = GLX_PBUFFER_HEIGHT; surface_attrs[i++] = sfc->h; surface_attrs[i++] = 0; pbuf = glXCreatePbuffer(re->software.ob->disp, cfgs[0], surface_attrs); XFree(cfgs); if (!pbuf) { ERR("GLX failed to create a pbuffer"); return NULL; } return (void*)(intptr_t)pbuf; #endif } static int evgl_eng_pbuffer_surface_destroy(void *data, void *surface) { /* EVGLINIT(re, 0); */ if (!data) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return 0; } if (!surface) { ERR("Invalid surface."); glsym_evas_gl_common_error_set(EVAS_GL_BAD_SURFACE); return 0; } #ifdef GL_GLES Render_Engine *re = data; eglDestroySurface(eng_get_ob(re)->egl_disp, (EGLSurface)surface); #else Render_Output_GL_Generic *re = data; GLXPbuffer pbuf = (GLXPbuffer)(intptr_t) surface; glXDestroyPbuffer(re->software.ob->disp, pbuf); #endif return 1; } // This function should create a surface that can be used for offscreen rendering // and still be bindable to a texture in Evas main GL context. // For now, this will create an X pixmap... Ideally it should be able to create // a bindable pbuffer surface or just an FBO if that is supported and it can // be shared with Evas. // FIXME: Avoid passing evgl_engine around like that. static void * evgl_eng_indirect_surface_create(EVGL_Engine *evgl EINA_UNUSED, void *data, EVGL_Surface *evgl_sfc, Evas_GL_Config *cfg, int w, int h) { Render_Engine *re = data; #ifdef GL_GLES Eina_Bool alpha = EINA_FALSE; #endif int colordepth; Pixmap px; if (!re || !evgl_sfc || !cfg) { glsym_evas_gl_common_error_set(EVAS_GL_BAD_PARAMETER); return NULL; } if ((w < 1) || (h < 1)) { ERR("Inconsistent parameters, not creating any surface!"); glsym_evas_gl_common_error_set(EVAS_GL_BAD_PARAMETER); return NULL; } /* Choose appropriate pixmap depth */ if (cfg->color_format == EVAS_GL_RGBA_8888) { #ifdef GL_GLES alpha = EINA_TRUE; #endif colordepth = 32; } else if (cfg->color_format == EVAS_GL_RGB_888) colordepth = 24; else // this could also be XDefaultDepth but this case shouldn't happen colordepth = 24; px = XCreatePixmap(eng_get_ob(re)->disp, eng_get_ob(re)->win, w, h, colordepth); if (!px) { ERR("Failed to create XPixmap!"); glsym_evas_gl_common_error_set(EVAS_GL_BAD_ALLOC); return NULL; } #ifdef GL_GLES EGLSurface egl_sfc; EGLConfig egl_cfg; int i, num = 0, best = -1; EGLConfig configs[200]; int config_attrs[40]; Eina_Bool found = EINA_FALSE; int msaa = 0, depth = 0, stencil = 0; Visual *visual = NULL; Eina_Bool retried = EINA_FALSE; EGLint val = 0; /* Now we need to iterate over all EGL configurations to check the compatible * ones and finally check their visual ID. */ if ((cfg->depth_bits > EVAS_GL_DEPTH_NONE) && (cfg->depth_bits <= EVAS_GL_DEPTH_BIT_32)) depth = 8 * ((int) cfg->depth_bits); if ((cfg->stencil_bits > EVAS_GL_STENCIL_NONE) && (cfg->stencil_bits <= EVAS_GL_STENCIL_BIT_16)) stencil = 1 << ((int) cfg->stencil_bits - 1); if ((cfg->multisample_bits > EVAS_GL_MULTISAMPLE_NONE) && (cfg->multisample_bits <= EVAS_GL_MULTISAMPLE_HIGH)) msaa = evgl->caps.msaa_samples[(int) cfg->multisample_bits - 1]; try_again: i = 0; config_attrs[i++] = EGL_SURFACE_TYPE; config_attrs[i++] = EGL_PIXMAP_BIT; config_attrs[i++] = EGL_RENDERABLE_TYPE; if (cfg->gles_version == EVAS_GL_GLES_3_X) config_attrs[i++] = EGL_OPENGL_ES3_BIT; else if (cfg->gles_version == EVAS_GL_GLES_2_X) config_attrs[i++] = EGL_OPENGL_ES2_BIT; else config_attrs[i++] = EGL_OPENGL_ES_BIT; if (alpha) { config_attrs[i++] = EGL_ALPHA_SIZE; config_attrs[i++] = 1; // should it be 8? DBG("Requesting RGBA pixmap"); } else { config_attrs[i++] = EGL_ALPHA_SIZE; config_attrs[i++] = 0; } if (depth) { depth = 8 * ((int) cfg->depth_bits); config_attrs[i++] = EGL_DEPTH_SIZE; config_attrs[i++] = depth; DBG("Requesting depth buffer size %d", depth); } if (stencil) { stencil = 1 << ((int) cfg->stencil_bits - 1); config_attrs[i++] = EGL_STENCIL_SIZE; config_attrs[i++] = stencil; DBG("Requesting stencil buffer size %d", stencil); } if (msaa) { msaa = evgl->caps.msaa_samples[(int) cfg->multisample_bits - 1]; config_attrs[i++] = EGL_SAMPLE_BUFFERS; config_attrs[i++] = 1; config_attrs[i++] = EGL_SAMPLES; config_attrs[i++] = msaa; DBG("Requesting MSAA buffer with %d samples", msaa); } config_attrs[i++] = EGL_NONE; config_attrs[i++] = 0; if (!eglChooseConfig(eng_get_ob(re)->egl_disp, config_attrs, configs, 200, &num) || !num) { int err = eglGetError(); ERR("eglChooseConfig() can't find any configs, error: %x", err); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); XFreePixmap(eng_get_ob(re)->disp, px); return NULL; } DBG("Found %d potential configurations", num); for (i = 0; (i < num) && !found; i++) { VisualID visid = 0; XVisualInfo *xvi, vi_in; XRenderPictFormat *fmt; int nvi = 0, j; if (!eglGetConfigAttrib(eng_get_ob(re)->egl_disp, configs[i], EGL_NATIVE_VISUAL_ID, &val)) continue; // Find matching visuals. Only alpha & depth are really valid here. visid = val; vi_in.screen = eng_get_ob(re)->screen; vi_in.visualid = visid; xvi = XGetVisualInfo(eng_get_ob(re)->disp, VisualScreenMask | VisualIDMask, &vi_in, &nvi); if (xvi) { for (j = 0; (j < nvi) && !found; j++) { if (xvi[j].depth >= colordepth) { if (best < 0) best = i; if (alpha) { fmt = XRenderFindVisualFormat(eng_get_ob(re)->disp, xvi[j].visual); if (fmt && (fmt->direct.alphaMask)) found = EINA_TRUE; } else found = EINA_TRUE; } } if (found) { egl_cfg = configs[i]; visual = xvi[j].visual; XFree(xvi); break; } XFree(xvi); } } if (!found) { if (num && (best >= 0)) { ERR("No matching config found. Trying with EGL config #%d", best); egl_cfg = configs[best]; } else if (msaa && !retried) { ERR("Trying again without MSAA."); msaa = 0; retried = EINA_TRUE; goto try_again; } else { // This config will probably not work, but we try anyways. // NOTE: Maybe it would be safer to just return NULL here, leaving // the app responsible for changing its config. ERR("XGetVisualInfo failed. Trying with the window's EGL config."); egl_cfg = eng_get_ob(re)->egl_config; } } egl_sfc = eglCreatePixmapSurface(eng_get_ob(re)->egl_disp, egl_cfg, px, NULL); if (!egl_sfc) { int err = eglGetError(); ERR("eglCreatePixmapSurface failed with error: %x", err); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); XFreePixmap(eng_get_ob(re)->disp, px); return NULL; } if (extn_have_y_inverted && eglGetConfigAttrib(eng_get_ob(re)->egl_disp, egl_cfg, EGL_Y_INVERTED_NOK, &val)) evgl_sfc->yinvert = val; else evgl_sfc->yinvert = 1; evgl_sfc->indirect = EINA_TRUE; evgl_sfc->indirect_sfc = egl_sfc; evgl_sfc->indirect_sfc_native = (void *)(intptr_t) px; evgl_sfc->indirect_sfc_visual = visual; evgl_sfc->indirect_sfc_config = egl_cfg; DBG("Successfully created indirect surface: Pixmap %lu EGLSurface %p", px, egl_sfc); return evgl_sfc; #else // TODO/FIXME: do the same as with EGL above... ERR("GLX support is not fully implemented for indirect surface"); evgl_sfc->indirect = EINA_TRUE; evgl_sfc->indirect_sfc_native = (void *)(intptr_t) px; evgl_sfc->indirect_sfc = (void *)(intptr_t) px; evgl_sfc->indirect_sfc_visual = eng_get_ob(re)->info->info.visual; // FIXME: Check this! return evgl_sfc; #endif } // This function should destroy the indirect surface as well as the X pixmap static int evgl_eng_indirect_surface_destroy(void *data, EVGL_Surface *evgl_sfc) { Render_Engine *re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); glsym_evas_gl_common_error_set(EVAS_GL_NOT_INITIALIZED); return 0; } #ifdef GL_GLES if ((!evgl_sfc) || (!evgl_sfc->indirect_sfc)) { ERR("Invalid surface"); glsym_evas_gl_common_error_set(EVAS_GL_BAD_SURFACE); return 0; } eglDestroySurface(eng_get_ob(re)->egl_disp, (EGLSurface)evgl_sfc->indirect_sfc); #endif if (!evgl_sfc->indirect_sfc_native) { ERR("Inconsistent parameters, not freeing XPixmap for indirect surface!"); glsym_evas_gl_common_error_set(EVAS_GL_BAD_PARAMETER); return 0; } XFreePixmap(eng_get_ob(re)->disp, (Pixmap)evgl_sfc->indirect_sfc_native); return 1; } static void * evgl_eng_gles_context_create(void *data, EVGL_Context *share_ctx, EVGL_Surface *sfc) { Render_Engine *re = data; if (!re) return NULL; #ifdef GL_GLES EGLContext context = EGL_NO_CONTEXT; int context_attrs[3]; EGLConfig config; if (!share_ctx) { ERR("Share context not set, Unable to retrieve GLES version"); return NULL; } context_attrs[0] = EGL_CONTEXT_CLIENT_VERSION; context_attrs[1] = share_ctx->version; context_attrs[2] = EGL_NONE; if (!sfc || !sfc->indirect_sfc_config) { ERR("Surface is not set! Creating context anyways but evas_eglMakeCurrent " "might very well fail with EGL_BAD_MATCH (0x3009)"); config = eng_get_ob(re)->egl_config; } else config = sfc->indirect_sfc_config; context = eglCreateContext(eng_get_ob(re)->egl_disp, config, share_ctx->context, context_attrs); if (!context) { int err = eglGetError(); ERR("eglCreateContext failed with error 0x%x", err); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); return NULL; } DBG("Successfully created context for indirect rendering."); return context; #else CRI("Support for indirect rendering contexts is not implemented for GLX"); (void) share_ctx; (void) sfc; return NULL; #endif } static void evgl_eng_native_win_surface_config_get(void *data, int *win_depth, int *win_stencil, int *win_msaa) { Render_Engine *re = data; if (!re) return; if (win_depth) *win_depth = eng_get_ob(re)->detected.depth_buffer_size; if (win_stencil) *win_stencil = eng_get_ob(re)->detected.stencil_buffer_size; if (win_msaa) *win_msaa = eng_get_ob(re)->detected.msaa; DBG("Window config(depth %d, stencil %d, msaa %d)", eng_get_ob(re)->detected.depth_buffer_size, eng_get_ob(re)->detected.stencil_buffer_size, eng_get_ob(re)->detected.msaa); } static const EVGL_Interface evgl_funcs = { evgl_eng_display_get, evgl_eng_evas_surface_get, evgl_eng_native_window_create, evgl_eng_native_window_destroy, evgl_eng_window_surface_create, evgl_eng_window_surface_destroy, evgl_eng_context_create, evgl_eng_context_destroy, evgl_eng_make_current, evgl_eng_proc_address_get, evgl_eng_string_get, evgl_eng_rotation_angle_get, evgl_eng_pbuffer_surface_create, evgl_eng_pbuffer_surface_destroy, evgl_eng_indirect_surface_create, evgl_eng_indirect_surface_destroy, evgl_eng_gles_context_create, evgl_eng_native_win_surface_config_get, }; //----------------------------------------------------------// static inline int _has_ext(const char *exts, const char *ext) { if (!exts || !ext) return EINA_FALSE; return strstr(exts, ext) != NULL; } static void gl_symbols(void) { static int done = 0; if (done) return; #define LINK2GENERIC(sym) \ glsym_##sym = dlsym(RTLD_DEFAULT, #sym); \ if (!glsym_##sym) ERR("Could not find function '%s'", #sym); // Get function pointer to evas_gl_common that is now provided through the link of GL_Generic. LINK2GENERIC(evas_gl_common_image_all_unload); LINK2GENERIC(evas_gl_common_image_ref); LINK2GENERIC(evas_gl_common_image_unref); LINK2GENERIC(evas_gl_common_image_new_from_data); LINK2GENERIC(evas_gl_common_image_native_disable); LINK2GENERIC(evas_gl_common_image_free); LINK2GENERIC(evas_gl_common_image_native_enable); LINK2GENERIC(evas_gl_common_context_new); LINK2GENERIC(evas_gl_common_context_flush); LINK2GENERIC(evas_gl_common_context_free); LINK2GENERIC(evas_gl_common_context_use); LINK2GENERIC(evas_gl_common_context_newframe); LINK2GENERIC(evas_gl_common_context_done); LINK2GENERIC(evas_gl_common_context_resize); LINK2GENERIC(evas_gl_common_buffer_dump); LINK2GENERIC(evas_gl_preload_render_lock); LINK2GENERIC(evas_gl_preload_render_unlock); LINK2GENERIC(evas_gl_preload_render_relax); LINK2GENERIC(evas_gl_preload_init); LINK2GENERIC(evas_gl_preload_shutdown); LINK2GENERIC(evgl_engine_shutdown); LINK2GENERIC(evgl_native_surface_buffer_get); LINK2GENERIC(evgl_native_surface_yinvert_get); LINK2GENERIC(evgl_current_native_context_get); LINK2GENERIC(evas_gl_symbols); LINK2GENERIC(evas_gl_common_error_get); LINK2GENERIC(evas_gl_common_error_set); LINK2GENERIC(evas_gl_common_current_context_get); LINK2GENERIC(evas_gl_common_shaders_flush); #define FINDSYM(dst, sym, typ) if (!dst) dst = (typ)dlsym(RTLD_DEFAULT, sym); #ifdef GL_GLES FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressKHR", glsym_func_eng_fn); FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressEXT", glsym_func_eng_fn); FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressARB", glsym_func_eng_fn); FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddress", glsym_func_eng_fn); #else FINDSYM(glsym_glXGetProcAddress, "glXGetProcAddressEXT", glsym_func_eng_fn); FINDSYM(glsym_glXGetProcAddress, "glXGetProcAddressARB", glsym_func_eng_fn); FINDSYM(glsym_glXGetProcAddress, "glXGetProcAddress", glsym_func_eng_fn); #endif #undef FINDSYM done = 1; } void eng_gl_symbols(Outbuf *ob) { static int done = 0; const char *exts; if (done) return; /* GetProcAddress() may not return NULL, even if the extension is not * supported. Nvidia drivers since version 360 never return NULL, thus * we need to always match the function name with their full extension * name. Other drivers tend to return NULL for glX/egl prefixed names, but * this could change in the future. * * -- jpeg, 2016/08/04 */ #ifdef GL_GLES #define FINDSYM(dst, sym, ext, typ) do { \ if (!dst) { \ if (_has_ext(exts, ext) && glsym_eglGetProcAddress) \ dst = (typ) glsym_eglGetProcAddress(sym); \ if (!dst) \ dst = (typ) dlsym(RTLD_DEFAULT, sym); \ }} while (0) // Find EGL extensions exts = eglQueryString(ob->egl_disp, EGL_EXTENSIONS); // Find GL extensions glsym_evas_gl_symbols((void*)glsym_eglGetProcAddress, exts); LINK2GENERIC(evas_gl_common_eglCreateImage); LINK2GENERIC(evas_gl_common_eglDestroyImage); FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamage", NULL, glsym_func_uint); FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageEXT", "EGL_EXT_swap_buffers_with_damage", glsym_func_uint); FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageKHR", "EGL_KHR_swap_buffers_with_damage", glsym_func_uint); FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageINTEL", "EGL_INTEL_swap_buffers_with_damage", glsym_func_uint); FINDSYM(glsym_eglSetDamageRegionKHR, "eglSetDamageRegionKHR", "EGL_KHR_partial_update", glsym_func_uint); FINDSYM(glsym_eglQueryWaylandBufferWL, "eglQueryWaylandBufferWL", "EGL_WL_bind_wayland_display", glsym_func_uint); // This is a GL extension exts = (const char *) glGetString(GL_EXTENSIONS); FINDSYM(glsym_glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES", "GL_OES_EGL_image", glsym_func_void); FINDSYM(glsym_glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES", "GL_OES_EGL_image_external", glsym_func_void); #else #define FINDSYM(dst, sym, ext, typ) do { \ if (!dst) { \ if (_has_ext(exts, ext) && glsym_glXGetProcAddress) \ dst = (typ) glsym_glXGetProcAddress(sym); \ if (!dst) \ dst = (typ) dlsym(RTLD_DEFAULT, sym); \ }} while (0) // Find GLX extensions exts = glXQueryExtensionsString((Display *) ob->disp, ob->screen); // Find GL extensions glsym_evas_gl_symbols((void*)glsym_glXGetProcAddress, exts); FINDSYM(glsym_glXBindTexImage, "glXBindTexImage", NULL, glsym_func_void); FINDSYM(glsym_glXBindTexImage, "glXBindTexImageEXT", "GLX_EXT_texture_from_pixmap", glsym_func_void); FINDSYM(glsym_glXBindTexImage, "glXBindTexImageARB", "GLX_ARB_render_texture", glsym_func_void); FINDSYM(glsym_glXReleaseTexImage, "glXReleaseTexImage", NULL, glsym_func_void); FINDSYM(glsym_glXReleaseTexImage, "glXReleaseTexImageEXT", "GLX_EXT_texture_from_pixmap", glsym_func_void); FINDSYM(glsym_glXReleaseTexImage, "glXReleaseTexImageARB", "GLX_ARB_render_texture", glsym_func_void); FINDSYM(glsym_glXGetVideoSync, "glXGetVideoSyncSGI", "GLX_SGI_video_sync", glsym_func_int); FINDSYM(glsym_glXWaitVideoSync, "glXWaitVideoSyncSGI", "GLX_SGI_video_sync", glsym_func_int); // GLX 1.3 FINDSYM(glsym_glXCreatePixmap, "glXCreatePixmap", NULL, glsym_func_xid); FINDSYM(glsym_glXDestroyPixmap, "glXDestroyPixmap", NULL, glsym_func_void); FINDSYM(glsym_glXQueryDrawable, "glXQueryDrawable", NULL, glsym_func_void); // swap interval: MESA and SGI take (interval) FINDSYM(glsym_glXSwapIntervalSGI, "glXSwapIntervalMESA", "GLX_MESA_swap_control", glsym_func_int); FINDSYM(glsym_glXSwapIntervalSGI, "glXSwapIntervalSGI", "GLX_SGI_swap_control", glsym_func_int); // swap interval: EXT takes (dpy, drawable, interval) FINDSYM(glsym_glXSwapIntervalEXT, "glXSwapIntervalEXT", "GLX_EXT_swap_control", glsym_func_void); FINDSYM(glsym_glXReleaseBuffersMESA, "glXReleaseBuffersMESA", "GLX_MESA_release_buffers", glsym_func_void); #endif #undef FINDSYM done = 1; } static void gl_extn_veto(Render_Engine *re) { const char *str = NULL; #ifdef GL_GLES str = eglQueryString(eng_get_ob(re)->egl_disp, EGL_EXTENSIONS); if (str) { const char *s; if (getenv("EVAS_GL_INFO")) printf("EGL EXTN:\n%s\n", str); // Disable Partial Rendering if ((s = getenv("EVAS_GL_PARTIAL_DISABLE")) && atoi(s)) { extn_have_buffer_age = 0; glsym_eglSwapBuffersWithDamage = NULL; glsym_eglSetDamageRegionKHR = NULL; } if (!strstr(str, "EGL_EXT_buffer_age")) { if (!strstr(str, "EGL_KHR_partial_update")) extn_have_buffer_age = 0; } if (!strstr(str, "EGL_KHR_partial_update")) { glsym_eglSetDamageRegionKHR = NULL; } if (!strstr(str, "EGL_NOK_texture_from_pixmap")) { extn_have_y_inverted = 0; } else { const GLubyte *vendor, *renderer; vendor = glGetString(GL_VENDOR); renderer = glGetString(GL_RENDERER); // XXX: workaround mesa bug! // looking for mesa and intel build which is known to // advertise the EGL_NOK_texture_from_pixmap extension // but not set it correctly. guessing vendor/renderer // strings will be like the following: // OpenGL vendor string: Intel Open Source Technology Center // OpenGL renderer string: Mesa DRI Intel(R) Sandybridge Desktop if (((vendor) && (strstr((const char *)vendor, "Intel"))) && ((renderer) && (strstr((const char *)renderer, "Mesa"))) && ((renderer) && (strstr((const char *)renderer, "Intel"))) ) extn_have_y_inverted = 0; } if ((!strstr(str, "EGL_EXT_swap_buffers_with_damage")) && (!strstr(str, "EGL_KHR_swap_buffers_with_damage"))) { glsym_eglSwapBuffersWithDamage = NULL; } if (strstr(str, "EGL_TIZEN_image_native_surface")) { eng_get_ob(re)->gl_context->shared->info.egl_tbm_ext = 1; } } else { if (getenv("EVAS_GL_INFO")) printf("NO EGL EXTN!\n"); extn_have_buffer_age = 0; } #else str = glXQueryExtensionsString(eng_get_ob(re)->info->info.display, eng_get_ob(re)->info->info.screen); if (str) { const char *str2; char *tmpstr; size_t sz = 0; sz = strlen(str); str2 = glXGetClientString(eng_get_ob(re)->info->info.display, GLX_EXTENSIONS); if (str2) sz += 1 + strlen(str2); tmpstr = alloca(sz + 1); strcpy(tmpstr, str); if (str2) { strcat(tmpstr, " "); if (str2) strcat(tmpstr, str2); } if (getenv("EVAS_GL_INFO")) printf("GLX EXTN:\n%s\n", tmpstr); if (!strstr(tmpstr, "_texture_from_pixmap")) { glsym_glXBindTexImage = NULL; glsym_glXReleaseTexImage = NULL; } if (!strstr(tmpstr, "GLX_SGI_video_sync")) { glsym_glXGetVideoSync = NULL; glsym_glXWaitVideoSync = NULL; } if (!strstr(tmpstr, "GLX_EXT_buffer_age")) { extn_have_buffer_age = 0; } if (!strstr(tmpstr, "GLX_EXT_swap_control")) { glsym_glXSwapIntervalEXT = NULL; } if (!strstr(tmpstr, "GLX_SGI_swap_control")) { glsym_glXSwapIntervalSGI = NULL; } if (!strstr(tmpstr, "GLX_MESA_release_buffers")) { glsym_glXReleaseBuffersMESA = NULL; } } else { if (getenv("EVAS_GL_INFO")) printf("NO GLX EXTN!\n"); glsym_glXBindTexImage = NULL; glsym_glXReleaseTexImage = NULL; glsym_glXGetVideoSync = NULL; glsym_glXWaitVideoSync = NULL; extn_have_buffer_age = 0; glsym_glXSwapIntervalEXT = NULL; glsym_glXSwapIntervalSGI = NULL; glsym_glXReleaseBuffersMESA = NULL; } #endif } int _evas_engine_GL_X11_log_dom = -1; /* function tables - filled in later (func and parent func) */ static Evas_Func func, pfunc; static void eng_output_info_setup(void *info) { Evas_Engine_Info_GL_X11 *einfo = info; einfo->func.best_visual_get = eng_best_visual_get; einfo->func.best_colormap_get = eng_best_colormap_get; einfo->func.best_depth_get = eng_best_depth_get; einfo->render_mode = EVAS_RENDER_MODE_BLOCKING; } static void eng_outbuf_idle_flush(Outbuf *ob) { if (glsym_evas_gl_common_shaders_flush) glsym_evas_gl_common_shaders_flush(ob->gl_context->shared); } static void _re_winfree(Render_Engine *re) { if (!eng_get_ob(re)->surf) return; glsym_evas_gl_preload_render_relax(eng_preload_make_current, eng_get_ob(re)); eng_window_unsurf(eng_get_ob(re)); } static void * eng_output_setup(void *engine, void *in, unsigned int w, unsigned int h) { Evas_Engine_Info_GL_X11 *info = in; Render_Engine *re = NULL; Outbuf *ob = NULL; Render_Output_Swap_Mode swap_mode; swap_mode = evas_render_engine_gl_swap_mode_get(info->swap_mode); // Set this env var to dump files every frame // Or set the global var in gdb to 1|0 to turn it on and off if (getenv("EVAS_GL_SWAP_BUFFER_DEBUG_ALWAYS")) swap_buffer_debug = 1; if (swap_buffer_debug_mode == -1) { if ( #if defined(HAVE_GETUID) && defined(HAVE_GETEUID) (getuid() == geteuid()) && #endif ((debug_dir = getenv("EVAS_GL_SWAP_BUFFER_DEBUG_DIR")))) { int stat; // Create a directory with 0775 permission stat = mkdir(debug_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); if ((!stat) || errno == EEXIST) swap_buffer_debug_mode = 1; } else swap_buffer_debug_mode = 0; } if (!initted) { glsym_evas_gl_preload_init(); } #ifdef GL_GLES #else int eb, evb; if (!glXQueryExtension(info->info.display, &eb, &evb)) return 0; #endif re = calloc(1, sizeof(Render_Engine)); if (!re) return NULL; ob = eng_window_new(info, info->info.display, info->info.drawable, info->info.screen, info->info.visual, info->info.colormap, info->info.depth, w, h, info->indirect, info->info.destination_alpha, info->info.rotation, swap_mode, info->depth_bits, info->stencil_bits, info->msaa_bits); if (!ob) goto on_error; if (!evas_render_engine_gl_generic_init(engine, &re->generic, ob, eng_outbuf_swap_mode, eng_outbuf_get_rot, eng_outbuf_reconfigure, eng_outbuf_region_first_rect, #ifdef GL_GLES eng_outbuf_damage_region_set, #else NULL, #endif eng_outbuf_new_region_for_update, eng_outbuf_push_updated_region, NULL, eng_outbuf_idle_flush, eng_outbuf_flush, NULL, eng_window_free, eng_window_use, eng_outbuf_gl_context_get, eng_outbuf_egl_display_get, eng_gl_context_new, eng_gl_context_use, &evgl_funcs, w, h)) goto on_error; gl_wins++; evas_render_engine_software_generic_merge_mode_set(&re->generic.software); if (!initted) { gl_extn_veto(re); // evgl_engine_init(re, &evgl_funcs); initted = 1; } eng_window_use(eng_get_ob(re)); return re; on_error: if (ob) eng_window_free(ob); free(re); return NULL; } static int eng_output_update(void *engine EINA_UNUSED, void *data, void *in, unsigned int w, unsigned int h) { Evas_Engine_Info_GL_X11 *info = in; Render_Engine *re = data; Render_Output_Swap_Mode swap_mode; swap_mode = evas_render_engine_gl_swap_mode_get(info->swap_mode); if (eng_get_ob(re) && _re_wincheck(eng_get_ob(re))) { if ((info->info.display != eng_get_ob(re)->disp) || (info->info.drawable != eng_get_ob(re)->win) || (info->info.screen != eng_get_ob(re)->screen) || (info->info.visual != eng_get_ob(re)->visual) || (info->info.colormap != eng_get_ob(re)->colormap) || (info->info.depth != eng_get_ob(re)->depth) || (info->depth_bits != eng_get_ob(re)->depth_bits) || (info->stencil_bits != eng_get_ob(re)->stencil_bits) || (info->msaa_bits != eng_get_ob(re)->msaa_bits) || (info->info.destination_alpha != eng_get_ob(re)->alpha)) { Outbuf *ob; gl_wins--; ob = eng_window_new(info, info->info.display, info->info.drawable, info->info.screen, info->info.visual, info->info.colormap, info->info.depth, w, h, info->indirect, info->info.destination_alpha, info->info.rotation, swap_mode, info->depth_bits, info->stencil_bits, info->msaa_bits); if (!ob) return 0; eng_window_use(ob); evas_render_engine_software_generic_update(&re->generic.software, ob, w, h); gl_wins++; } else if ((eng_get_ob(re)->w != w) || (eng_get_ob(re)->h != h) || (eng_get_ob(re)->info->info.rotation != eng_get_ob(re)->rot)) { eng_outbuf_reconfigure(eng_get_ob(re), w, h, eng_get_ob(re)->info->info.rotation, 0); evas_render_engine_software_generic_update(&re->generic.software, re->generic.software.ob, w, h); } } eng_window_use(eng_get_ob(re)); return 1; } static void eng_output_free(void *engine, void *data) { Render_Engine *re; re = (Render_Engine *)data; if (re) { #ifndef GL_GLES Display *disp = eng_get_ob(re)->disp; Window win = eng_get_ob(re)->win; #endif glsym_evas_gl_preload_render_relax(eng_preload_make_current, eng_get_ob(re)); #if 0 #ifdef GL_GLES // Destroy the resource surface // Only required for EGL case if (re->surface) eglDestroySurface(eng_get_ob(re)->egl_disp, re->surface); #endif // Destroy the resource context _destroy_internal_context(re, context); #endif if (gl_wins == 1) glsym_evgl_engine_shutdown(re); evas_render_engine_software_generic_clean(engine, &re->generic.software); #ifndef GL_GLES if (glsym_glXReleaseBuffersMESA) glsym_glXReleaseBuffersMESA(disp, win); #endif gl_wins--; free(re); } if ((initted == 1) && (gl_wins == 0)) { glsym_evas_gl_preload_shutdown(); initted = 0; } } /* vsync games - not for now though */ #define VSYNC_TO_SCREEN 1 Eina_Bool eng_preload_make_current(void *data, void *doit) { Outbuf *ob = data; if (doit) { #ifdef GL_GLES if (!evas_eglMakeCurrent(ob->egl_disp, ob->egl_surface, ob->egl_surface, ob->egl_context)) return EINA_FALSE; #else if (!__glXMakeContextCurrent(ob->info->info.display, ob->glxwin, ob->context)) { ERR("glXMakeContextCurrent(%p, %p, %p) failed", ob->info->info.display, (void *)ob->win, (void *)ob->context); GLERRV("__glXMakeContextCurrent"); return EINA_FALSE; } #endif } else { #ifdef GL_GLES if (!evas_eglMakeCurrent(ob->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) return EINA_FALSE; #else if (!__glXMakeContextCurrent(ob->info->info.display, 0, NULL)) { ERR("glXMakeContextCurrent(%p, None, NULL) failed", ob->info->info.display); GLERRV("__glXMakeContextCurrent"); return EINA_FALSE; } #endif } return EINA_TRUE; } static Eina_Bool eng_canvas_alpha_get(void *engine) { Render_Engine *re = (Render_Engine *)engine; return re->generic.software.ob->alpha; } static void eng_output_dump(void *engine, void *data) { Render_Engine *re = data; Render_Engine_GL_Generic *e = engine; eng_window_use(eng_get_ob(re)); generic_cache_dump(e->software.surface_cache); evas_common_image_image_all_unload(); evas_common_font_font_all_unload(); glsym_evas_gl_common_image_all_unload(eng_get_ob(re)->gl_context); _re_winfree(re); } static void * eng_gl_current_context_get(void *engine EINA_UNUSED) { EVGL_Context *ctx; EVGLNative_Context context; ctx = glsym_evas_gl_common_current_context_get(); if (!ctx) return NULL; context = glsym_evgl_current_native_context_get(ctx); #ifdef GL_GLES if (evas_eglGetCurrentContext() == context) return ctx; #else if (glXGetCurrentContext() == context) return ctx; #endif return NULL; } static int eng_gl_error_get(void *engine) { int err; if ((err = glsym_evas_gl_common_error_get(engine)) != EVAS_GL_SUCCESS) goto end; #ifdef GL_GLES err = eglGetError() - EGL_SUCCESS; #else Render_Engine *re = engine; if (!eng_get_ob(re)->win) err = EVAS_GL_BAD_DISPLAY; else if (!eng_get_ob(re)->info) err = EVAS_GL_BAD_SURFACE; #endif end: glsym_evas_gl_common_error_set(EVAS_GL_SUCCESS); return err; } ///////////////////////////////////////////////////////////////////////// // // // FIXME: this is enabled so updates happen - but its SLOOOOOOOOOOOOOOOW // (i am sure this is the reason) not to mention seemingly superfluous. but // i need to enable it for it to work on fglrx at least. havent tried nvidia. // // why is this the case? does anyone know? has anyone tried it on other gfx // drivers? // //#define GLX_TEX_PIXMAP_RECREATE 1 static void _native_bind_cb(void *image) { Evas_GL_Image *im = image; Native *n = im->native.data; if (n->ns.type == EVAS_NATIVE_SURFACE_X11) { #ifdef GL_GLES if (n->ns_data.x11.surface) { if (n->ns_data.x11.multiple_buffer) { EGLint err; if (!glsym_evas_gl_common_eglDestroyImage) { ERR("Try eglDestroyImage()/eglCreateImage() on EGL with no support"); return; } glsym_evas_gl_common_eglDestroyImage(im->native.disp, n->ns_data.x11.surface); if ((err = eglGetError()) != EGL_SUCCESS) { ERR("eglDestroyImage() failed."); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); } n->ns_data.x11.surface = glsym_evas_gl_common_eglCreateImage(im->native.disp, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (void *)n->ns_data.x11.pixmap, NULL); if (!n->ns_data.x11.surface) ERR("eglCreateImage() for Pixmap 0x%#lx failed: %#x", n->ns_data.x11.pixmap, eglGetError()); } if (glsym_glEGLImageTargetTexture2DOES) { glsym_glEGLImageTargetTexture2DOES(im->native.target, n->ns_data.x11.surface); GLERRV("glsym_glEGLImageTargetTexture2DOES"); } else ERR("Try glEGLImageTargetTexture2DOES on EGL with no support"); } #else # ifdef GLX_BIND_TO_TEXTURE_TARGETS_EXT if (glsym_glXBindTexImage) { glsym_glXBindTexImage(im->native.disp, (XID)n->ns_data.x11.surface, GLX_FRONT_LEFT_EXT, NULL); GLERRV("glsym_glXBindTexImage"); } else ERR("Try glXBindTexImage on GLX with no support"); # endif #endif } else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) { glBindTexture(im->native.target, n->ns.data.opengl.texture_id); } else if (n->ns.type == EVAS_NATIVE_SURFACE_TBM) { #ifdef GL_GLES if (n->ns_data.tbm.surface) { if (glsym_glEGLImageTargetTexture2DOES) { glsym_glEGLImageTargetTexture2DOES(im->native.target, n->ns_data.tbm.surface); GLERRV("glsym_glEGLImageTargetTexture2DOES"); } else ERR("Try glEGLImageTargetTexture2DOES on EGL with no support"); } #endif } else if (n->ns.type == EVAS_NATIVE_SURFACE_EVASGL) { if (n->ns_data.evasgl.surface) { Eina_Bool is_egl_image = EINA_FALSE; void *surface = NULL; if (glsym_evgl_native_surface_buffer_get) surface = glsym_evgl_native_surface_buffer_get(n->ns_data.evasgl.surface, &is_egl_image); if (is_egl_image) { #ifdef GL_GLES if (glsym_glEGLImageTargetTexture2DOES) { glsym_glEGLImageTargetTexture2DOES(im->native.target, surface); GLERRV("glsym_glEGLImageTargetTexture2DOES"); } else #endif ERR("Try glEGLImageTargetTexture2DOES on EGL with no support"); } else { glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr_t)surface); } } } else if (n->ns.type == EVAS_NATIVE_SURFACE_WL) { #ifdef GL_GLES # ifdef HAVE_WAYLAND if (n->ns_data.wl_surface.surface) { if (glsym_glEGLImageTargetTexture2DOES) { glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, n->ns_data.wl_surface.surface); GLERRV("glsym_glEGLImageTargetTexture2DOES"); } else ERR("Try glEGLImageTargetTexture2DOES on EGL with no support"); } # endif #endif } } static void _native_unbind_cb(void *image) { Evas_GL_Image *im = image; Native *n = im->native.data; if (n->ns.type == EVAS_NATIVE_SURFACE_X11) { #ifdef GL_GLES // nothing #else # ifdef GLX_BIND_TO_TEXTURE_TARGETS_EXT if (glsym_glXReleaseTexImage) { glsym_glXReleaseTexImage(im->native.disp, (XID)(n->ns_data.x11.surface), GLX_FRONT_LEFT_EXT); } else ERR("Try glXReleaseTexImage on GLX with no support"); # endif #endif } else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) { glBindTexture(im->native.target, 0); } else if (n->ns.type == EVAS_NATIVE_SURFACE_TBM) { // nothing } else if (n->ns.type == EVAS_NATIVE_SURFACE_EVASGL) { #ifdef GL_GLES // nothing #else glBindTexture(GL_TEXTURE_2D, 0); #endif } } static void _native_free_cb(void *image) { Evas_GL_Image *im = image; Native *n = im->native.data; uint32_t pmid, texid; #ifdef GL_GLES # ifdef HAVE_WAYLAND void *wlid; # endif #endif if (n->ns.type == EVAS_NATIVE_SURFACE_X11) { pmid = n->ns_data.x11.pixmap; eina_hash_del(im->native.shared->native_pm_hash, &pmid, im); #ifdef GL_GLES if (n->ns_data.x11.surface) { int err; if (glsym_evas_gl_common_eglDestroyImage) { glsym_evas_gl_common_eglDestroyImage(im->native.disp, n->ns_data.x11.surface); if ((err = eglGetError()) != EGL_SUCCESS) { ERR("eglDestroyImage() failed."); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); } } else ERR("Try eglDestroyImage on EGL with no support"); } #else # ifdef GLX_BIND_TO_TEXTURE_TARGETS_EXT if (n->ns_data.x11.surface) { if (im->native.loose) { if (glsym_glXReleaseTexImage) { glsym_glXReleaseTexImage(im->native.disp, (XID)n->ns_data.x11.surface, GLX_FRONT_LEFT_EXT); } else ERR("Try glXReleaseTexImage on GLX with no support"); } if (glsym_glXDestroyPixmap) { glsym_glXDestroyPixmap(im->native.disp, (XID)n->ns_data.x11.surface); GLERRV("glsym_glXDestroyPixmap"); } else ERR("Try glXDestroyPixmap on GLX with no support"); n->ns_data.x11.surface = 0; } # endif #endif } else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) { texid = n->ns.data.opengl.texture_id; eina_hash_del(im->native.shared->native_tex_hash, &texid, im); } else if (n->ns.type == EVAS_NATIVE_SURFACE_TBM) { eina_hash_del(im->native.shared->native_tbm_hash, &n->ns_data.tbm.buffer, im); #ifdef GL_GLES if (n->ns_data.tbm.surface) { int err; if (glsym_evas_gl_common_eglDestroyImage) { glsym_evas_gl_common_eglDestroyImage(im->native.disp, n->ns_data.tbm.surface); if ((err = eglGetError()) != EGL_SUCCESS) { ERR("eglDestroyImage() failed."); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); } } else ERR("Try eglDestroyImage on EGL with no support"); } #endif } else if (n->ns.type == EVAS_NATIVE_SURFACE_EVASGL) { eina_hash_del(im->native.shared->native_evasgl_hash, &n->ns.data.evasgl.surface, im); } else if (n->ns.type == EVAS_NATIVE_SURFACE_WL) { #ifdef GL_GLES # ifdef HAVE_WAYLAND wlid = (void*)n->ns_data.wl_surface.wl_buf; eina_hash_del(im->native.shared->native_wl_hash, &wlid, image); if (n->ns_data.wl_surface.surface) { if (glsym_evas_gl_common_eglDestroyImage) { glsym_evas_gl_common_eglDestroyImage(im->native.disp, n->ns_data.wl_surface.surface); if (eglGetError() != EGL_SUCCESS) ERR("eglDestroyImage() failed."); } else ERR("Try eglDestroyImage on EGL with no support"); } # endif #endif } im->native.data = NULL; im->native.func.bind = NULL; im->native.func.unbind = NULL; im->native.func.free = NULL; free(n); } static int _native_yinvert_cb(void *image) { Evas_GL_Image *im = image; Native *n = im->native.data; int yinvert = 0, val; // Yinvert callback should only be used for EVAS_NATIVE_SURFACE_EVASGL type now, // as yinvert value is not changed for other types. if (n->ns.type == EVAS_NATIVE_SURFACE_X11) { #if GL_GLES if (extn_have_y_inverted && eglGetConfigAttrib(im->native.disp, n->ns_data.x11.config, EGL_Y_INVERTED_NOK, &val)) yinvert = val; #else glXGetFBConfigAttrib(im->native.disp, n->ns_data.x11.config, GLX_Y_INVERTED_EXT, &val); if (val) yinvert = 1; #endif } else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) { yinvert = 0; } else if (n->ns.type == EVAS_NATIVE_SURFACE_TBM) { yinvert = 1; } else if (n->ns.type == EVAS_NATIVE_SURFACE_EVASGL) { yinvert = glsym_evgl_native_surface_yinvert_get(n->ns_data.evasgl.surface); } return yinvert; } static int eng_image_native_init(void *engine EINA_UNUSED, Evas_Native_Surface_Type type) { switch (type) { #ifdef GL_GLES case EVAS_NATIVE_SURFACE_TBM: return _evas_native_tbm_init(); #endif case EVAS_NATIVE_SURFACE_X11: case EVAS_NATIVE_SURFACE_OPENGL: case EVAS_NATIVE_SURFACE_EVASGL: return 1; #if defined(GL_GLES) && defined(HAVE_WAYLAND) case EVAS_NATIVE_SURFACE_WL: return (glsym_eglQueryWaylandBufferWL != NULL) ? 1 : 0; #endif default: ERR("Native surface type %d not supported!", type); return 0; } } static void eng_image_native_shutdown(void *engine EINA_UNUSED, Evas_Native_Surface_Type type) { switch (type) { #ifdef GL_GLES case EVAS_NATIVE_SURFACE_TBM: _evas_native_tbm_shutdown(); return; #endif case EVAS_NATIVE_SURFACE_X11: case EVAS_NATIVE_SURFACE_OPENGL: case EVAS_NATIVE_SURFACE_EVASGL: #if defined(GL_GLES) && defined(HAVE_WAYLAND) case EVAS_NATIVE_SURFACE_WL: #endif return; default: ERR("Native surface type %d not supported!", type); return; } } static void * eng_image_native_set(void *engine, void *image, void *native) { const Evas_Native_Surface *ns = native; Evas_Engine_GL_Context *gl_context; Evas_GL_Image *im = image, *im2 = NULL; Visual *vis = NULL; Pixmap pm = 0; Native *n = NULL; uint32_t pmid, texid; unsigned int tex = 0; unsigned int fbo = 0; void *buffer = NULL; Outbuf *ob; #ifdef GL_GLES # ifdef HAVE_WAYLAND void *wlid, *wl_buf = NULL; # endif #endif gl_context = gl_generic_context_find(engine, 1); ob = gl_generic_any_output_get(engine); if (!im) { if ((ns) && (ns->type == EVAS_NATIVE_SURFACE_OPENGL)) { im = glsym_evas_gl_common_image_new_from_data(gl_context, ns->data.opengl.w, ns->data.opengl.h, NULL, 1, EVAS_COLORSPACE_ARGB8888); } else return NULL; } if (ns) { if (ns->type == EVAS_NATIVE_SURFACE_X11) { vis = ns->data.x11.visual; pm = ns->data.x11.pixmap; if (im->native.data) { Evas_Native_Surface *ens = im->native.data; if ((ens->data.x11.visual == vis) && (ens->data.x11.pixmap == pm)) return im; } } else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL) { tex = ns->data.opengl.texture_id; fbo = ns->data.opengl.framebuffer_id; if (im->native.data) { Evas_Native_Surface *ens = im->native.data; if ((ens->data.opengl.texture_id == tex) && (ens->data.opengl.framebuffer_id == fbo)) return im; } } else if (ns->type == EVAS_NATIVE_SURFACE_TBM) { buffer = ns->data.tbm.buffer; if (im->native.data) { Evas_Native_Surface *ens = im->native.data; if (ens->data.tbm.buffer == buffer) return im; } } else if (ns->type == EVAS_NATIVE_SURFACE_EVASGL) { buffer = ns->data.evasgl.surface; if (im->native.data) { Evas_Native_Surface *ens = im->native.data; if (ens->data.evasgl.surface == buffer) return im; } } else if (ns->type == EVAS_NATIVE_SURFACE_WL) { #ifdef GL_GLES # ifdef HAVE_WAYLAND wl_buf = ns->data.wl.legacy_buffer; if (im->native.data) { Evas_Native_Surface *ens; ens = im->native.data; if (ens->data.wl.legacy_buffer == wl_buf) return im; } # endif #endif } } if (!ns) { glsym_evas_gl_common_image_free(im); return NULL; } if (ns->type == EVAS_NATIVE_SURFACE_X11) { pmid = pm; im2 = eina_hash_find(gl_context->shared->native_pm_hash, &pmid); if (im2 == im) return im; if (im2) { n = im2->native.data; if (n) { glsym_evas_gl_common_image_ref(im2); glsym_evas_gl_common_image_free(im); return im2; } } } else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL) { texid = tex; im2 = eina_hash_find(gl_context->shared->native_tex_hash, &texid); if (im2 == im) return im; if (im2) { n = im2->native.data; if (n) { glsym_evas_gl_common_image_ref(im2); glsym_evas_gl_common_image_free(im); return im2; } } } else if (ns->type == EVAS_NATIVE_SURFACE_TBM) { im2 = eina_hash_find(gl_context->shared->native_tbm_hash, &buffer); if (im2 == im) return im; if (im2) { n = im2->native.data; if (n) { glsym_evas_gl_common_image_ref(im2); glsym_evas_gl_common_image_free(im); return im2; } } } else if (ns->type == EVAS_NATIVE_SURFACE_EVASGL) { im2 = eina_hash_find(gl_context->shared->native_evasgl_hash, &buffer); if (im2 == im) return im; if (im2) { n = im2->native.data; if (n) { glsym_evas_gl_common_image_ref(im2); glsym_evas_gl_common_image_free(im); return im2; } } } else if (ns->type == EVAS_NATIVE_SURFACE_WL) { #ifdef GL_GLES # ifdef HAVE_WAYLAND wlid = wl_buf; im2 = eina_hash_find(gl_context->shared->native_wl_hash, &wlid); if (im2 == im) return im; if (im2) { if((n = im2->native.data)) { glsym_evas_gl_common_image_ref(im2); glsym_evas_gl_common_image_free(im); return im2; } } # endif #endif } im2 = glsym_evas_gl_common_image_new_from_data(gl_context, im->w, im->h, NULL, im->alpha, EVAS_COLORSPACE_ARGB8888); glsym_evas_gl_common_image_free(im); im = im2; if (!im) return NULL; if (ns->type == EVAS_NATIVE_SURFACE_X11) { #ifdef GL_GLES if (native) { if (!glsym_evas_gl_common_eglDestroyImage) { ERR("Try eglCreateImage on EGL with no support"); return NULL; } n = calloc(1, sizeof(Native)); if (n) { EGLConfig egl_config; int config_attrs[20]; int num_config, i = 0; int yinvert = 1; // assume 32bit pixmap! :) config_attrs[i++] = EGL_RED_SIZE; config_attrs[i++] = 8; config_attrs[i++] = EGL_GREEN_SIZE; config_attrs[i++] = 8; config_attrs[i++] = EGL_BLUE_SIZE; config_attrs[i++] = 8; config_attrs[i++] = EGL_ALPHA_SIZE; config_attrs[i++] = 8; config_attrs[i++] = EGL_DEPTH_SIZE; config_attrs[i++] = 0; config_attrs[i++] = EGL_STENCIL_SIZE; config_attrs[i++] = 0; config_attrs[i++] = EGL_RENDERABLE_TYPE; if (gles3_supported) config_attrs[i++] = EGL_OPENGL_ES3_BIT_KHR; else config_attrs[i++] = EGL_OPENGL_ES2_BIT; config_attrs[i++] = EGL_SURFACE_TYPE; config_attrs[i++] = EGL_PIXMAP_BIT; config_attrs[i++] = EGL_NONE; if (!eglChooseConfig(ob->egl_disp, config_attrs, &egl_config, 1, &num_config)) { int err = eglGetError(); ERR("eglChooseConfig() failed for pixmap %#lx, " "num_config = %i with error %d", pm, num_config, err); glsym_evas_gl_common_error_set(err - EGL_SUCCESS); free(n); return NULL; } else { int val; if (extn_have_y_inverted && eglGetConfigAttrib(ob->egl_disp, egl_config, EGL_Y_INVERTED_NOK, &val)) yinvert = val; } memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); n->ns_data.x11.pixmap = pm; n->ns_data.x11.visual = vis; n->ns_data.x11.surface = glsym_evas_gl_common_eglCreateImage(ob->egl_disp, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (void *)pm, NULL); if ((ns->version < 4) || ((ns->version == 4) && !(ns->data.x11.multiple_buffer == 1))) n->ns_data.x11.multiple_buffer = 0; else n->ns_data.x11.multiple_buffer = 1; if (ob->detected.no_multi_buffer_native) n->ns_data.x11.multiple_buffer = 0; if (!n->ns_data.x11.surface) { ERR("eglCreateImage() for Pixmap %#lx failed: %#x", pm, eglGetError()); free(n); return NULL; } n->ns_data.x11.config = (void *)egl_config; im->native.yinvert = yinvert; im->native.loose = 0; im->native.disp = ob->egl_disp; im->native.shared = gl_context->shared; im->native.data = n; im->native.func.bind = _native_bind_cb; im->native.func.unbind = _native_unbind_cb; im->native.func.free = _native_free_cb; im->native.target = GL_TEXTURE_2D; im->native.mipmap = 0; eina_hash_add(ob->gl_context->shared->native_pm_hash, &pmid, im); glsym_evas_gl_common_image_native_enable(im); } } #else # ifdef GLX_BIND_TO_TEXTURE_TARGETS_EXT if (native) { int dummy; unsigned int w, h, depth = 32, border; Window wdummy; // fixme: round trip :( XGetGeometry(ob->disp, pm, &wdummy, &dummy, &dummy, &w, &h, &border, &depth); if (depth <= 32) { n = calloc(1, sizeof(Native)); if (n) { int pixmap_att[20], i; int config_attrs[40], num = 0; int tex_format = 0, tex_target = 0, yinvert = 0, mipmap = 0; unsigned int target = 0; GLXFBConfig *configs; i = 0; config_attrs[i++] = GLX_BUFFER_SIZE; config_attrs[i++] = depth; if (depth == 32) { config_attrs[i++] = GLX_BIND_TO_TEXTURE_RGBA_EXT; config_attrs[i++] = 1; } else { config_attrs[i++] = GLX_BIND_TO_TEXTURE_RGB_EXT; config_attrs[i++] = 1; } #ifndef GLX_VISUAL_ID # define GLX_VISUAL_ID 0x800b #endif config_attrs[i++] = GLX_VISUAL_ID; config_attrs[i++] = XVisualIDFromVisual(vis); #ifndef GLX_SAMPLE_BUFFERS # define GLX_SAMPLE_BUFFERS 0x186a0 #endif config_attrs[i++] = GLX_SAMPLE_BUFFERS; config_attrs[i++] = 0; config_attrs[i++] = GLX_DEPTH_SIZE; config_attrs[i++] = 0; config_attrs[i++] = GLX_STENCIL_SIZE; config_attrs[i++] = 0; config_attrs[i++] = GLX_AUX_BUFFERS; config_attrs[i++] = 0; config_attrs[i++] = GLX_STEREO; config_attrs[i++] = 0; config_attrs[i++] = 0; configs = glXChooseFBConfig(ob->disp, ob->screen, config_attrs, &num); if (configs) { int j = 0, val = 0, found = 0; try_again: for (j = 0; j < num; j++) { if (found == 0) { XVisualInfo *vi; vi = glXGetVisualFromFBConfig(ob->disp, configs[j]); if (!vi) continue; if (vi->depth != (int)depth) continue; XFree(vi); glXGetFBConfigAttrib(ob->disp, configs[j], GLX_BUFFER_SIZE, &val); if (val != (int) depth) continue; } glXGetFBConfigAttrib(ob->disp, configs[j], GLX_DRAWABLE_TYPE, &val); if (!(val & GLX_PIXMAP_BIT)) continue; tex_format = GLX_TEXTURE_FORMAT_RGB_EXT; glXGetFBConfigAttrib(ob->disp, configs[j], GLX_ALPHA_SIZE, &val); if ((depth == 32) && (!val)) continue; if (val > 0) { glXGetFBConfigAttrib(ob->disp, configs[j], GLX_BIND_TO_TEXTURE_RGBA_EXT, &val); if (val) tex_format = GLX_TEXTURE_FORMAT_RGBA_EXT; } else { glXGetFBConfigAttrib(ob->disp, configs[j], GLX_BIND_TO_TEXTURE_RGB_EXT, &val); if (val) tex_format = GLX_TEXTURE_FORMAT_RGB_EXT; } glXGetFBConfigAttrib(ob->disp, configs[j], GLX_Y_INVERTED_EXT, &val); if (val) yinvert = 1; glXGetFBConfigAttrib(ob->disp, configs[j], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &val); tex_target = val; glXGetFBConfigAttrib(ob->disp, configs[j], GLX_BIND_TO_MIPMAP_TEXTURE_EXT, &val); mipmap = val; n->ns_data.x11.config = configs[j]; found = 1; break; } if (found == 0) { found = -1; goto try_again; } XFree(configs); } eina_hash_add(gl_context->shared->native_pm_hash, &pmid, im); if ((tex_target & GLX_TEXTURE_2D_BIT_EXT)) target = GLX_TEXTURE_2D_EXT; else if ((tex_target & GLX_TEXTURE_RECTANGLE_BIT_EXT)) { ERR("rect!!! (not handled)"); target = GLX_TEXTURE_RECTANGLE_EXT; } if (!target) { ERR("broken tex-from-pixmap"); if (!(tex_target & GLX_TEXTURE_2D_BIT_EXT)) target = GLX_TEXTURE_RECTANGLE_EXT; else if (!(tex_target & GLX_TEXTURE_RECTANGLE_BIT_EXT)) target = GLX_TEXTURE_2D_EXT; } i = 0; pixmap_att[i++] = GLX_TEXTURE_FORMAT_EXT; pixmap_att[i++] = tex_format; pixmap_att[i++] = GLX_MIPMAP_TEXTURE_EXT; pixmap_att[i++] = mipmap; if (target) { pixmap_att[i++] = GLX_TEXTURE_TARGET_EXT; pixmap_att[i++] = target; } pixmap_att[i++] = 0; memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); n->ns_data.x11.pixmap = pm; n->ns_data.x11.visual = vis; if (glsym_glXCreatePixmap) n->ns_data.x11.surface = (void *)glsym_glXCreatePixmap(ob->disp, n->ns_data.x11.config, n->ns_data.x11.pixmap, pixmap_att); else ERR("Try glXCreatePixmap on GLX with no support"); if (n->ns_data.x11.surface) { // printf("%p: new native texture for %x | %4i x %4i @ %2i = %p\n", // n, pm, w, h, depth, n->surface); if (!target) { ERR("no target :("); if (glsym_glXQueryDrawable) glsym_glXQueryDrawable(ob->disp, n->ns_data.x11.pixmap, GLX_TEXTURE_TARGET_EXT, &target); } if (target == GLX_TEXTURE_2D_EXT) { im->native.target = GL_TEXTURE_2D; im->native.mipmap = mipmap; } # ifdef GL_TEXTURE_RECTANGLE_ARB else if (target == GLX_TEXTURE_RECTANGLE_EXT) { im->native.target = GL_TEXTURE_RECTANGLE_ARB; im->native.mipmap = 0; } # endif else { im->native.target = GL_TEXTURE_2D; im->native.mipmap = 0; ERR("still unknown target"); } } else ERR("GLX Pixmap create fail"); im->native.yinvert = yinvert; im->native.loose = ob->detected.loose_binding; im->native.disp = ob->disp; im->native.shared = gl_context->shared; im->native.data = n; im->native.func.bind = _native_bind_cb; im->native.func.unbind = _native_unbind_cb; im->native.func.free = _native_free_cb; glsym_evas_gl_common_image_native_enable(im); } } } # endif #endif } else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL) { if (native) { n = calloc(1, sizeof(Native)); if (n) { memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); eina_hash_add(gl_context->shared->native_tex_hash, &texid, im); n->ns_data.opengl.surface = 0; im->native.yinvert = 0; im->native.loose = 0; #ifdef GL_GLES im->native.disp = ob->egl_disp; #else im->native.disp = ob->disp; #endif im->native.shared = gl_context->shared; im->native.data = n; im->native.func.bind = _native_bind_cb; im->native.func.unbind = _native_unbind_cb; im->native.func.free = _native_free_cb; im->native.target = GL_TEXTURE_2D; im->native.mipmap = 0; // FIXME: need to implement mapping sub texture regions // x, y, w, h for possible texture atlasing glsym_evas_gl_common_image_native_enable(im); } } } else if (ns->type == EVAS_NATIVE_SURFACE_TBM) { #ifdef GL_GLES if (native) { n = calloc(1, sizeof(Native)); if (n) { eina_hash_add(gl_context->shared->native_tbm_hash, &buffer, im); memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); n->ns_data.tbm.buffer = buffer; if (glsym_evas_gl_common_eglDestroyImage) n->ns_data.tbm.surface = glsym_evas_gl_common_eglCreateImage(ob->egl_disp, EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, (void *)buffer, NULL); else ERR("Try eglCreateImage on EGL with no support"); if (!n->ns_data.tbm.surface) ERR("eglCreateImage() for %p failed", buffer); im->native.yinvert = 1; im->native.loose = 0; im->native.disp = ob->egl_disp; im->native.shared = gl_context->shared; im->native.data = n; im->native.func.bind = _native_bind_cb; im->native.func.unbind = _native_unbind_cb; im->native.func.free = _native_free_cb; im->native.target = GL_TEXTURE_EXTERNAL_OES; im->native.mipmap = 0; glsym_evas_gl_common_image_native_enable(im); } } #endif } else if (ns->type == EVAS_NATIVE_SURFACE_EVASGL) { if (native) { n = calloc(1, sizeof(Native)); if (n) { memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); eina_hash_add(gl_context->shared->native_evasgl_hash, &buffer, im); n->ns_data.evasgl.surface = ns->data.evasgl.surface; im->native.yinvert = 0; im->native.loose = 0; #ifdef GL_GLES im->native.disp = ob->egl_disp; #else im->native.disp = ob->disp; #endif im->native.shared = gl_context->shared; im->native.data = n; im->native.func.bind = _native_bind_cb; im->native.func.unbind = _native_unbind_cb; im->native.func.free = _native_free_cb; im->native.func.yinvert = _native_yinvert_cb; im->native.target = GL_TEXTURE_2D; im->native.mipmap = 0; // FIXME: need to implement mapping sub texture regions // x, y, w, h for possible texture atlasing glsym_evas_gl_common_image_native_enable(im); } } } else if (ns->type == EVAS_NATIVE_SURFACE_WL) { #ifdef GL_GLES # ifdef HAVE_WAYLAND if (native) { if ((n = calloc(1, sizeof(Native)))) { EGLAttrib attribs[3]; int format, yinvert = 1; glsym_eglQueryWaylandBufferWL(ob->egl_disp, wl_buf, EGL_TEXTURE_FORMAT, &format); if ((format != EGL_TEXTURE_RGB) && (format != EGL_TEXTURE_RGBA)) { ERR("eglQueryWaylandBufferWL() %d format is not supported ", format); glsym_evas_gl_common_image_free(im); free(n); return NULL; } # ifndef EGL_WAYLAND_PLANE_WL # define EGL_WAYLAND_PLANE_WL 0x31D6 # endif # ifndef EGL_WAYLAND_BUFFER_WL # define EGL_WAYLAND_BUFFER_WL 0x31D5 # endif attribs[0] = EGL_WAYLAND_PLANE_WL; attribs[1] = 0; //if plane is 1 then 0, if plane is 2 then 1 attribs[2] = EGL_NONE; memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); if (glsym_eglQueryWaylandBufferWL(ob->egl_disp, wl_buf, EGL_WAYLAND_Y_INVERTED_WL, &yinvert) == EGL_FALSE) yinvert = 1; eina_hash_add(gl_context->shared->native_wl_hash, &wlid, im); n->ns_data.wl_surface.wl_buf = wl_buf; if (glsym_evas_gl_common_eglDestroyImage) n->ns_data.wl_surface.surface = glsym_evas_gl_common_eglCreateImage(ob->egl_disp, NULL, EGL_WAYLAND_BUFFER_WL, wl_buf, attribs); else { ERR("Try eglCreateImage on EGL with no support"); eina_hash_del(gl_context->shared->native_wl_hash, &wlid, im); glsym_evas_gl_common_image_free(im); free(n); return NULL; } if (!n->ns_data.wl_surface.surface) { ERR("eglCreatePixmapSurface() for %p failed", wl_buf); eina_hash_del(gl_context->shared->native_wl_hash, &wlid, im); glsym_evas_gl_common_image_free(im); free(n); return NULL; } //XXX: workaround for mesa-10.2.8 // mesa's eglQueryWaylandBufferWL() with EGL_WAYLAND_Y_INVERTED_WL works incorrect. //im->native.yinvert = yinvert; im->native.yinvert = 1; im->native.loose = 0; im->native.disp = ob->egl_disp; im->native.shared = gl_context->shared; im->native.data = n; im->native.func.bind = _native_bind_cb; im->native.func.unbind = _native_unbind_cb; im->native.func.free = _native_free_cb; im->native.target = GL_TEXTURE_2D; im->native.mipmap = 0; glsym_evas_gl_common_image_native_enable(im); } } # endif #endif } return im; } static int module_open(Evas_Module *em) { static Eina_Bool xrm_inited = EINA_FALSE; const char *platform_env = NULL; if (!xrm_inited) { xrm_inited = EINA_TRUE; XrmInitialize(); } if (!em) return 0; /* get whatever engine module we inherit from */ if (!_evas_module_engine_inherit(&pfunc, "gl_generic", sizeof (Evas_Engine_Info_GL_X11))) return 0; if (_evas_engine_GL_X11_log_dom < 0) _evas_engine_GL_X11_log_dom = eina_log_domain_register ("evas-gl_x11", EVAS_DEFAULT_LOG_COLOR); if (_evas_engine_GL_X11_log_dom < 0) { EINA_LOG_ERR("Can not create a module log domain."); return 0; } if (partial_render_debug == -1) { if (getenv("EVAS_GL_PARTIAL_DEBUG")) partial_render_debug = 1; else partial_render_debug = 0; } // partial_render_debug = 1; /* store it for later use */ func = pfunc; /* now to override methods */ #define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_) ORD(output_info_setup); ORD(output_setup); ORD(output_update); ORD(canvas_alpha_get); ORD(output_free); ORD(output_dump); ORD(image_native_init); ORD(image_native_shutdown); ORD(image_native_set); ORD(gl_error_get); // gl_current_surface_get is in gl generic ORD(gl_current_context_get); if (!(platform_env = getenv("EGL_PLATFORM"))) setenv("EGL_PLATFORM", "x11", 0); gl_symbols(); if (!platform_env) unsetenv("EGL_PLATFORM"); /* now advertise out own api */ em->functions = (void *)(&func); return 1; } static void module_close(Evas_Module *em EINA_UNUSED) { if (_evas_engine_GL_X11_log_dom >= 0) { eina_log_domain_unregister(_evas_engine_GL_X11_log_dom); _evas_engine_GL_X11_log_dom = -1; } } static Evas_Module_Api evas_modapi = { EVAS_MODULE_API_VERSION, "gl_x11", "none", { module_open, module_close } }; EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, gl_x11); #ifndef EVAS_STATIC_BUILD_GL_XLIB EVAS_EINA_MODULE_DEFINE(engine, gl_x11); #endif /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/