forked from enlightenment/efl
3088 lines
99 KiB
C
3088 lines
99 KiB
C
#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 <dlfcn.h> /* 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 :*/
|