From e8b1320f91838a29891c6a5b377160e27a0adcf5 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 4 Aug 2024 20:27:26 +0200 Subject: Add option to choose render api (glx or egl) in window creation --- include/mgl/gl.h | 37 +++- include/mgl/gl_macro.h | 13 ++ include/mgl/window/window.h | 6 + src/gl.c | 142 +++++++++++--- src/window/window.c | 469 +++++++++++++++++++++++++++++++++----------- 5 files changed, 520 insertions(+), 147 deletions(-) diff --git a/include/mgl/gl.h b/include/mgl/gl.h index c96beea..397d608 100644 --- a/include/mgl/gl.h +++ b/include/mgl/gl.h @@ -10,10 +10,25 @@ typedef struct _XDisplay Display; typedef struct __GLXcontextRec *GLXContext; typedef unsigned long GLXDrawable; typedef struct __GLXFBConfigRec *GLXFBConfig; +typedef void(*__GLXextFuncPtr)(void); + +typedef void (*FUNC_glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval); +typedef int (*FUNC_glXSwapIntervalMESA)(unsigned int interval); +typedef int (*FUNC_glXSwapIntervalSGI)(int interval); + +typedef void* EGLDisplay; +typedef void* EGLNativeDisplayType; +typedef uintptr_t EGLNativeWindowType; +typedef void* EGLConfig; +typedef void* EGLSurface; +typedef void* EGLContext; typedef struct { - void *handle; + void *gl_library; + void *glx_library; + void *egl_library; + __GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName); GLXContext (*glXCreateNewContext)(Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, int direct); int (*glXMakeContextCurrent)(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); void (*glXDestroyContext)(Display *dpy, GLXContext ctx); @@ -21,6 +36,20 @@ typedef struct { GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems); _XVisualInfo* (*glXGetVisualFromFBConfig)(Display *dpy, GLXFBConfig config); + EGLDisplay (*eglGetDisplay)(EGLNativeDisplayType display_id); + unsigned int (*eglInitialize)(EGLDisplay dpy, int32_t *major, int32_t *minor); + unsigned int (*eglTerminate)(EGLDisplay dpy); + unsigned int (*eglChooseConfig)(EGLDisplay dpy, const int32_t *attrib_list, EGLConfig *configs, int32_t config_size, int32_t *num_config); + EGLSurface (*eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const int32_t *attrib_list); + EGLContext (*eglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const int32_t *attrib_list); + unsigned int (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); + unsigned int (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); + unsigned int (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); + unsigned int (*eglSwapInterval)(EGLDisplay dpy, int32_t interval); + unsigned int (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); + unsigned int (*eglBindAPI)(unsigned int api); + unsigned int (*eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, int32_t attribute, int32_t *value); + void (*glViewport)(int x, int y, int width, int height); void (*glScissor)(int x, int y, int width, int height); void (*glClearColor)(float red, float green, float blue, float alpha); @@ -82,9 +111,9 @@ typedef struct { void (*glFinish)(void); /* Optional*/ - void (*glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval); - int (*glXSwapIntervalMESA)(unsigned int interval); - int (*glXSwapIntervalSGI)(int interval); + FUNC_glXSwapIntervalEXT glXSwapIntervalEXT; + FUNC_glXSwapIntervalMESA glXSwapIntervalMESA; + FUNC_glXSwapIntervalSGI glXSwapIntervalSGI; void (*glGenerateMipmap)(unsigned int target); } mgl_gl; diff --git a/include/mgl/gl_macro.h b/include/mgl/gl_macro.h index ba2d3f1..bfeffce 100644 --- a/include/mgl/gl_macro.h +++ b/include/mgl/gl_macro.h @@ -91,4 +91,17 @@ #define GL_SCISSOR_TEST 0x0C11 +#define EGL_SUCCESS 0x3000 +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_RED_SIZE 0x3024 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_NONE 0x3038 +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 +#define EGL_NATIVE_VISUAL_ID 0x302E + #endif /* MGL_GL_MACRO_H */ diff --git a/include/mgl/window/window.h b/include/mgl/window/window.h index fdffd8d..7370df9 100644 --- a/include/mgl/window/window.h +++ b/include/mgl/window/window.h @@ -66,6 +66,11 @@ typedef enum { MGL_WINDOW_TYPE_NOTIFICATION /* Also sets the window as always on top */ } mgl_window_type; +typedef enum { + MGL_RENDER_API_GLX, + MGL_RENDER_API_EGL +} mgl_render_api; + /* TODO: Some of these parameters only apply to new window */ typedef struct { mgl_vec2i position; @@ -81,6 +86,7 @@ typedef struct { const char *class_name; mgl_window_type window_type; /* default: normal */ mgl_window_handle transient_for_window; + mgl_render_api render_api; /* default: MGL_RENDER_API_GLX */ } mgl_window_create_params; typedef enum { diff --git a/src/gl.c b/src/gl.c index 4ac022a..77e867a 100644 --- a/src/gl.c +++ b/src/gl.c @@ -1,6 +1,7 @@ #include "../include/mgl/gl.h" #include #include +#include typedef struct { void **func; @@ -18,22 +19,8 @@ static void* dlsym_print_fail(void *handle, const char *name, int required) { return sym; } -int mgl_gl_load(mgl_gl *self) { - const char *glx_path = "libGL.so.1"; - self->handle = dlopen(glx_path, RTLD_LAZY); - if(!self->handle) { - fprintf(stderr, "mgl error:dlopen(\"%s\", RTLD_LAZY) failed\n", glx_path); - return -1; - } - - dlsym_assign required_dlsym[] = { - { (void**)&self->glXCreateNewContext, "glXCreateNewContext" }, - { (void**)&self->glXMakeContextCurrent, "glXMakeContextCurrent" }, - { (void**)&self->glXDestroyContext, "glXDestroyContext" }, - { (void**)&self->glXSwapBuffers, "glXSwapBuffers" }, - { (void**)&self->glXChooseFBConfig, "glXChooseFBConfig" }, - { (void**)&self->glXGetVisualFromFBConfig, "glXGetVisualFromFBConfig" }, - +static int mgl_gl_load_gl(mgl_gl *self) { + const dlsym_assign required_dlsym[] = { { (void**)&self->glViewport, "glViewport" }, { (void**)&self->glScissor, "glScissor" }, { (void**)&self->glClearColor, "glClearColor" }, @@ -98,32 +85,133 @@ int mgl_gl_load(mgl_gl *self) { }; for(int i = 0; required_dlsym[i].func; ++i) { - *required_dlsym[i].func = dlsym_print_fail(self->handle, required_dlsym[i].name, 1); - if(!*required_dlsym[i].func) { - mgl_gl_unload(self); + *required_dlsym[i].func = dlsym_print_fail(self->gl_library, required_dlsym[i].name, 1); + if(!*required_dlsym[i].func) return -1; - } } const dlsym_assign optional_dlsym[] = { - { (void**)&self->glXSwapIntervalEXT, "glXSwapIntervalEXT" }, - { (void**)&self->glXSwapIntervalMESA, "glXGetSwapIntervalMESA" }, - { (void**)&self->glXSwapIntervalSGI, "glXSwapIntervalSGI" }, { (void**)&self->glGenerateMipmap, "glGenerateMipmap" }, { NULL, NULL } }; for(int i = 0; optional_dlsym[i].func; ++i) { - *optional_dlsym[i].func = dlsym_print_fail(self->handle, optional_dlsym[i].name, 0); + *optional_dlsym[i].func = dlsym_print_fail(self->gl_library, optional_dlsym[i].name, 0); + } + + return 0; +} + +static int mgl_gl_load_glx(mgl_gl *self) { + const dlsym_assign required_dlsym[] = { + { (void**)&self->glXGetProcAddress, "glXGetProcAddress" }, + { (void**)&self->glXCreateNewContext, "glXCreateNewContext" }, + { (void**)&self->glXMakeContextCurrent, "glXMakeContextCurrent" }, + { (void**)&self->glXDestroyContext, "glXDestroyContext" }, + { (void**)&self->glXSwapBuffers, "glXSwapBuffers" }, + { (void**)&self->glXChooseFBConfig, "glXChooseFBConfig" }, + { (void**)&self->glXGetVisualFromFBConfig, "glXGetVisualFromFBConfig" }, + + { NULL, NULL } + }; + + for(int i = 0; required_dlsym[i].func; ++i) { + *required_dlsym[i].func = dlsym_print_fail(self->glx_library, required_dlsym[i].name, 1); + if(!*required_dlsym[i].func) + return -1; + } + + self->glXSwapIntervalEXT = (FUNC_glXSwapIntervalEXT)self->glXGetProcAddress((const unsigned char*)"glXSwapIntervalEXT"); + self->glXSwapIntervalMESA = (FUNC_glXSwapIntervalMESA)self->glXGetProcAddress((const unsigned char*)"glXSwapIntervalMESA"); + self->glXSwapIntervalSGI = (FUNC_glXSwapIntervalSGI)self->glXGetProcAddress((const unsigned char*)"glXSwapIntervalSGI"); + + return 0; +} + +static int mgl_gl_load_egl(mgl_gl *self) { + const dlsym_assign required_dlsym[] = { + { (void**)&self->eglGetDisplay, "eglGetDisplay" }, + { (void**)&self->eglInitialize, "eglInitialize" }, + { (void**)&self->eglTerminate, "eglTerminate" }, + { (void**)&self->eglChooseConfig, "eglChooseConfig" }, + { (void**)&self->eglCreateWindowSurface, "eglCreateWindowSurface" }, + { (void**)&self->eglCreateContext, "eglCreateContext" }, + { (void**)&self->eglMakeCurrent, "eglMakeCurrent" }, + { (void**)&self->eglDestroyContext, "eglDestroyContext" }, + { (void**)&self->eglDestroySurface, "eglDestroySurface" }, + { (void**)&self->eglSwapInterval, "eglSwapInterval" }, + { (void**)&self->eglSwapBuffers, "eglSwapBuffers" }, + { (void**)&self->eglBindAPI, "eglBindAPI" }, + { (void**)&self->eglGetConfigAttrib, "eglGetConfigAttrib" }, + + { NULL, NULL } + }; + + for(int i = 0; required_dlsym[i].func; ++i) { + *required_dlsym[i].func = dlsym_print_fail(self->egl_library, required_dlsym[i].name, 1); + if(!*required_dlsym[i].func) + return -1; + } + + return 0; +} + +int mgl_gl_load(mgl_gl *self) { + memset(self, 0, sizeof(*self)); + + self->gl_library = dlopen("libGL.so.1", RTLD_LAZY); + if(!self->gl_library) { + fprintf(stderr, "mgl error:dlopen(\"%s\", RTLD_LAZY) failed\n", "libGL.so.1"); + mgl_gl_unload(self); + return -1; + } + + self->glx_library = dlopen("libGLX.so.0", RTLD_LAZY); + if(!self->glx_library) { + fprintf(stderr, "mgl error:dlopen(\"%s\", RTLD_LAZY) failed\n", "libGLX.so.0"); + mgl_gl_unload(self); + return -1; + } + + self->egl_library = dlopen("libEGL.so.1", RTLD_LAZY); + if(!self->egl_library) { + fprintf(stderr, "mgl error:dlopen(\"%s\", RTLD_LAZY) failed\n", "libEGL.so.1"); + mgl_gl_unload(self); + return -1; + } + + if(mgl_gl_load_gl(self) != 0) { + mgl_gl_unload(self); + return -1; + } + + if(mgl_gl_load_glx(self) != 0) { + mgl_gl_unload(self); + return -1; + } + + if(mgl_gl_load_egl(self) != 0) { + mgl_gl_unload(self); + return -1; } return 0; } void mgl_gl_unload(mgl_gl *self) { - if(self->handle) { - dlclose(self->handle); - self->handle = NULL; + if(self->egl_library) { + dlclose(self->egl_library); + self->egl_library = NULL; + } + + if(self->glx_library) { + dlclose(self->glx_library); + self->glx_library = NULL; + } + + if(self->gl_library) { + dlclose(self->gl_library); + self->gl_library = NULL; } } diff --git a/src/window/window.c b/src/window/window.c index 8ba9f8e..5c44fa8 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -58,6 +58,283 @@ static bool x11_events_circular_buffer_pop(x11_events_circular_buffer *self, mgl typedef struct { GLXContext glx_context; + GLXFBConfig *fbconfigs; + GLXFBConfig fbconfig; + XVisualInfo *visual_info; +} x11_context_glx; + +static bool glx_context_choose(mgl_context *context, x11_context_glx *glx, bool alpha) { + const int attr[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DOUBLEBUFFER, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, alpha ? 8 : 0, + // TODO: + //GLX_DEPTH_SIZE, 0, + None + }; + + glx->fbconfigs = NULL; + glx->visual_info = NULL; + glx->fbconfig = NULL; + + int numfbconfigs = 0; + glx->fbconfigs = context->gl.glXChooseFBConfig(context->connection, DefaultScreen(context->connection), attr, &numfbconfigs); + for(int i = 0; i < numfbconfigs; i++) { + glx->visual_info = (XVisualInfo*)context->gl.glXGetVisualFromFBConfig(context->connection, glx->fbconfigs[i]); + if(!glx->visual_info) + continue; + + XRenderPictFormat *pict_format = XRenderFindVisualFormat(context->connection, glx->visual_info->visual); + if(!pict_format) { + XFree(glx->visual_info); + glx->visual_info = NULL; + continue; + } + + glx->fbconfig = glx->fbconfigs[i]; + if((alpha && pict_format->direct.alphaMask > 0) || (!alpha && pict_format->direct.alphaMask == 0)) + break; + + XFree(glx->visual_info); + glx->visual_info = NULL; + glx->fbconfig = NULL; + } + + if(!glx->visual_info) { + if(glx->fbconfigs) { + XFree(glx->fbconfigs); + glx->fbconfigs = NULL; + } + glx->fbconfig = NULL; + + fprintf(stderr, "mgl error: no appropriate visual found\n"); + return false; + } + + return true; +} + +static void x11_context_glx_deinit(x11_context_glx *self) { + mgl_context *context = mgl_get_context(); + + if(self->glx_context) { + context->gl.glXMakeContextCurrent(context->connection, None, None, NULL); + context->gl.glXDestroyContext(context->connection, self->glx_context); + self->glx_context = NULL; + } + + if(self->visual_info) { + XFree(self->visual_info); + self->visual_info = NULL; + } + + if(self->fbconfigs) { + XFree(self->fbconfigs); + self->fbconfigs = NULL; + } + + self->fbconfig = NULL; +} + +static bool x11_context_glx_init(x11_context_glx *self, bool alpha) { + mgl_context *context = mgl_get_context(); + memset(self, 0, sizeof(*self)); + + if(!glx_context_choose(context, self, alpha)) { + x11_context_glx_deinit(self); + return false; + } + + self->glx_context = context->gl.glXCreateNewContext(context->connection, self->fbconfig, GLX_RGBA_TYPE, 0, True); + if(!self->glx_context) { + fprintf(stderr, "mgl error: x11_context_glx_init: glXCreateContext failed\n"); + x11_context_glx_deinit(self); + return false; + } + + return true; +} + +static bool x11_context_glx_make_context_current(x11_context_glx *self, Window window) { + mgl_context *context = mgl_get_context(); + return context->gl.glXMakeContextCurrent(context->connection, window, window, self->glx_context) != 0; +} + +static void x11_context_glx_swap_buffers(x11_context_glx *self, Window window) { + (void)self; + mgl_context *context = mgl_get_context(); + context->gl.glXSwapBuffers(context->connection, window); +} + +static XVisualInfo* x11_context_glx_get_xvisual_info(x11_context_glx *self) { + return self->visual_info; +} + +static bool x11_context_glx_set_swap_interval(x11_context_glx *self, Window window, int enabled) { + (void)self; + mgl_context *context = mgl_get_context(); + + int result = 0; + if(context->gl.glXSwapIntervalEXT) { + context->gl.glXSwapIntervalEXT(context->connection, window, enabled ? 1 : 0); + } else if(context->gl.glXSwapIntervalMESA) { + result = context->gl.glXSwapIntervalMESA(enabled ? 1 : 0); + } else if(context->gl.glXSwapIntervalSGI) { + result = context->gl.glXSwapIntervalSGI(enabled ? 1 : 0); + } else { + static int warned = 0; + if (!warned) { + warned = 1; + fprintf(stderr, "mgl warning: setting vertical sync not supported\n"); + } + } + + if(result != 0) + fprintf(stderr, "mgl warning: setting vertical sync failed\n"); + + return result == 0; +} + +typedef struct { + EGLDisplay egl_display; + EGLSurface egl_surface; + EGLContext egl_context; + EGLConfig ecfg; + XVisualInfo *visual_info; +} x11_context_egl; + +static void x11_context_egl_deinit(x11_context_egl *self) { + mgl_context *context = mgl_get_context(); + + if(self->egl_context) { + context->gl.eglMakeCurrent(self->egl_display, NULL, NULL, NULL); + context->gl.eglDestroyContext(self->egl_display, self->egl_context); + self->egl_context = NULL; + } + + if(self->egl_surface) { + context->gl.eglDestroySurface(self->egl_display, self->egl_surface); + self->egl_surface = NULL; + } + + if(self->egl_display) { + context->gl.eglTerminate(self->egl_display); + self->egl_display = NULL; + } + + if(self->visual_info) { + XFree(self->visual_info); + self->visual_info = NULL; + } +} + +static bool x11_context_egl_init(x11_context_egl *self, bool alpha) { + mgl_context *context = mgl_get_context(); + memset(self, 0, sizeof(*self)); + + int32_t num_config = 0; + + const int32_t attr[] = { + EGL_BUFFER_SIZE, alpha ? 32 : 24, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, alpha ? 8 : 0, + // TODO: + //EGL_DEPTH_SIZE, 0, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE, EGL_NONE + }; + + const int32_t ctxattr[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE, EGL_NONE + }; + + context->gl.eglBindAPI(EGL_OPENGL_API); + + self->egl_display = context->gl.eglGetDisplay((EGLNativeDisplayType)context->connection); + if(!self->egl_display) { + fprintf(stderr, "gsr error: gsr_egl_create_window failed: eglGetDisplay failed\n"); + x11_context_egl_deinit(self); + return false; + } + + if(!context->gl.eglInitialize(self->egl_display, NULL, NULL)) { + fprintf(stderr, "gsr error: gsr_egl_create_window failed: eglInitialize failed\n"); + x11_context_egl_deinit(self); + return false; + } + + // TODO: Iterate all egl configs (eglGetConfigs) and match visuals to choose the correct one + if(!context->gl.eglChooseConfig(self->egl_display, attr, &self->ecfg, 1, &num_config) || num_config != 1) { + fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to find a matching config\n"); + x11_context_egl_deinit(self); + return false; + } + + self->egl_context = context->gl.eglCreateContext(self->egl_display, self->ecfg, NULL, ctxattr); + if(!self->egl_context) { + fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to create egl context\n"); + x11_context_egl_deinit(self); + return false; + } + + // TODO: Error check + int visual_id = 0; + context->gl.eglGetConfigAttrib(self->egl_display, self->ecfg, EGL_NATIVE_VISUAL_ID, &visual_id); + + XVisualInfo vi = {0}; + vi.visualid = visual_id; + int count = 0; + self->visual_info = XGetVisualInfo(context->connection, VisualIDMask, &vi, &count); + if(self->visual_info) { + // TODO: Check if the visual really is transparent with XRenderFindVisualFormat and alphaMask value, the same way its done for GLX + } + + return true; +} + +static bool x11_context_egl_make_context_current(x11_context_egl *self, Window window) { + (void)window; + mgl_context *context = mgl_get_context(); + + if(!self->egl_surface) { + self->egl_surface = context->gl.eglCreateWindowSurface(self->egl_display, self->ecfg, (EGLNativeWindowType)window, NULL); + if(!self->egl_surface) { + fprintf(stderr, "gsr error: x11_context_egl_make_context_current: failed to create window surface\n"); + return false; + } + } + + return context->gl.eglMakeCurrent(self->egl_display, self->egl_surface, self->egl_surface, self->egl_context) != 0; +} + +static void x11_context_egl_swap_buffers(x11_context_egl *self, Window window) { + (void)window; + mgl_context *context = mgl_get_context(); + context->gl.eglSwapBuffers(self->egl_display, self->egl_surface); +} + +static XVisualInfo* x11_context_egl_get_xvisual_info(x11_context_egl *self) { + return self->visual_info; +} + +static bool x11_context_egl_set_swap_interval(x11_context_egl *self, Window window, int enabled) { + (void)window; + mgl_context *context = mgl_get_context(); + return context->gl.eglSwapInterval(self->egl_display, enabled) == 1; +} + +typedef struct { + x11_context_glx glx; + x11_context_egl egl; + mgl_render_api render_api; + Colormap color_map; XIM xim; XIC xic; Atom clipboard_atom; @@ -83,10 +360,6 @@ typedef struct { Cursor invisible_cursor; unsigned int prev_keycode_pressed; bool key_was_released; - Colormap color_map; - GLXFBConfig *fbconfigs; - GLXFBConfig fbconfig; - XVisualInfo *visual_info; bool support_alpha; /* This only contains connected and active monitors */ @@ -104,62 +377,15 @@ typedef struct { static void x11_context_deinit(x11_context *self); -static bool glx_context_choose(mgl_context *context, GLXFBConfig **fbconfigs, GLXFBConfig *fbconfig, XVisualInfo **visual_info, bool alpha) { - const int attr[] = { - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_DOUBLEBUFFER, True, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, alpha ? 8 : 0, - GLX_DEPTH_SIZE, 0, - None - }; - - *fbconfigs = NULL; - *visual_info = NULL; - *fbconfig = NULL; - - int numfbconfigs = 0; - *fbconfigs = context->gl.glXChooseFBConfig(context->connection, DefaultScreen(context->connection), attr, &numfbconfigs); - for(int i = 0; i < numfbconfigs; i++) { - *visual_info = (XVisualInfo*)context->gl.glXGetVisualFromFBConfig(context->connection, (*fbconfigs)[i]); - if(!*visual_info) - continue; - - XRenderPictFormat *pict_format = XRenderFindVisualFormat(context->connection, (*visual_info)->visual); - if(!pict_format) { - XFree(*visual_info); - *visual_info = NULL; - continue; - } - - *fbconfig = (*fbconfigs)[i]; - if((alpha && pict_format->direct.alphaMask > 0) || (!alpha && pict_format->direct.alphaMask == 0)) - break; - - XFree(*visual_info); - *visual_info = NULL; - *fbconfig = NULL; - } - - if(!*visual_info) { - fprintf(stderr, "mgl error: no appropriate visual found\n"); - return false; - } +static int x11_context_init(x11_context *self, bool alpha, mgl_render_api render_api) { + mgl_context *context = mgl_get_context(); - return true; -} + memset(self, 0, sizeof(*self)); -static int x11_context_init(x11_context *self, bool alpha) { - mgl_context *context = mgl_get_context(); + self->render_api = render_api; /* TODO: Use CLIPBOARD_MANAGER and SAVE_TARGETS to save clipboard in clipboard manager on exit */ - self->glx_context = NULL; - self->xim = NULL; - self->xic = NULL; /* TODO: Create all of these with one XInternAtoms call instead */ self->clipboard_atom = XInternAtom(context->connection, "CLIPBOARD", False); self->targets_atom = XInternAtom(context->connection, "TARGETS", False); @@ -180,24 +406,24 @@ static int x11_context_init(x11_context *self, bool alpha) { self->net_wm_window_type_notification_atom = XInternAtom(context->connection, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False); self->net_wm_window_type_utility = XInternAtom(context->connection, "_NET_WM_WINDOW_TYPE_UTILITY", False); self->motif_wm_hints_atom = XInternAtom(context->connection, "_MOTIF_WM_HINTS", False); - self->default_cursor = None; - self->invisible_cursor = None; - - self->prev_keycode_pressed = 0; - self->key_was_released = false; - self->color_map = None; - self->fbconfigs = NULL; - self->fbconfig = NULL; - self->visual_info = NULL; self->support_alpha = alpha; - memset(self->monitors, 0, sizeof(self->monitors)); - self->num_monitors = 0; - - if(!glx_context_choose(context, &self->fbconfigs, &self->fbconfig, &self->visual_info, alpha)) { - x11_context_deinit(self); - return -1; + switch(self->render_api) { + case MGL_RENDER_API_GLX: { + if(!x11_context_glx_init(&self->glx, alpha)) { + x11_context_deinit(self); + return -1; + } + break; + } + case MGL_RENDER_API_EGL: { + if(!x11_context_egl_init(&self->egl, alpha)) { + x11_context_deinit(self); + return -1; + } + break; + } } self->default_cursor = XCreateFontCursor(context->connection, XC_arrow); @@ -267,23 +493,59 @@ void x11_context_deinit(x11_context *self) { self->xim = NULL; } - if(self->glx_context) { - context->gl.glXMakeContextCurrent(context->connection, None, None, NULL); - context->gl.glXDestroyContext(context->connection, self->glx_context); - self->glx_context = NULL; + switch(self->render_api) { + case MGL_RENDER_API_GLX: { + x11_context_glx_deinit(&self->glx); + break; + } + case MGL_RENDER_API_EGL: { + x11_context_egl_deinit(&self->egl); + break; + } } +} - if(self->visual_info) { - XFree(self->visual_info); - self->visual_info = NULL; +static bool x11_context_make_gl_context_current(x11_context *self, Window window) { + switch(self->render_api) { + case MGL_RENDER_API_GLX: + return x11_context_glx_make_context_current(&self->glx, window); + case MGL_RENDER_API_EGL: + return x11_context_egl_make_context_current(&self->egl, window); } + return false; +} - if(self->fbconfigs) { - XFree(self->fbconfigs); - self->fbconfigs = NULL; +static void x11_context_swap_buffers(x11_context *self, Window window) { + switch(self->render_api) { + case MGL_RENDER_API_GLX: { + x11_context_glx_swap_buffers(&self->glx, window); + break; + } + case MGL_RENDER_API_EGL: { + x11_context_egl_swap_buffers(&self->egl, window); + break; + } } +} - self->fbconfig = NULL; +static XVisualInfo* x11_context_get_xvisual_info(x11_context *self) { + switch(self->render_api) { + case MGL_RENDER_API_GLX: + return x11_context_glx_get_xvisual_info(&self->glx); + case MGL_RENDER_API_EGL: + return x11_context_egl_get_xvisual_info(&self->egl); + } + return NULL; +} + +static bool x11_context_set_swap_interval(x11_context *self, Window window, int enabled) { + switch(self->render_api) { + case MGL_RENDER_API_GLX: + return x11_context_glx_set_swap_interval(&self->glx, window, enabled); + case MGL_RENDER_API_EGL: + return x11_context_egl_set_swap_interval(&self->egl, window, enabled); + } + return false; } static bool x11_context_append_event(x11_context *self, const mgl_event *event) { @@ -431,26 +693,8 @@ static void monitor_callback_add_to_x11_context(const mgl_monitor *monitor, void /* TODO: Use gl OML present for other platforms than nvidia? nvidia doesn't support present yet */ /* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */ -static void set_vertical_sync_enabled(Window window, int enabled) { - int result = 0; - mgl_context *context = mgl_get_context(); - - if(context->gl.glXSwapIntervalEXT) { - context->gl.glXSwapIntervalEXT(context->connection, window, enabled ? 1 : 0); - } else if(context->gl.glXSwapIntervalMESA) { - result = context->gl.glXSwapIntervalMESA(enabled ? 1 : 0); - } else if(context->gl.glXSwapIntervalSGI) { - result = context->gl.glXSwapIntervalSGI(enabled ? 1 : 0); - } else { - static int warned = 0; - if (!warned) { - warned = 1; - fprintf(stderr, "mgl warning: setting vertical sync not supported\n"); - } - } - - if(result != 0) - fprintf(stderr, "mgl warning: setting vertical sync failed\n"); +static void set_vertical_sync_enabled(mgl_window *self, int enabled) { + x11_context_set_swap_interval(self->context, self->window, enabled); } static void mgl_window_set_frame_time_limit_monitor(mgl_window *self) { @@ -579,7 +823,7 @@ static int mgl_window_init(mgl_window *self, const char *title, const mgl_window } x11_context *x11_context = self->context; - if(x11_context_init(x11_context, params ? params->support_alpha : false) != 0) { + if(x11_context_init(x11_context, params ? params->support_alpha : false, params ? params->render_api : MGL_RENDER_API_GLX) != 0) { fprintf(stderr, "mgl error: x11_context_init failed\n"); mgl_window_deinit(self); return -1; @@ -595,14 +839,8 @@ static int mgl_window_init(mgl_window *self, const char *title, const mgl_window if(parent_window == 0) parent_window = DefaultRootWindow(context->connection); - x11_context->glx_context = context->gl.glXCreateNewContext(context->connection, x11_context->fbconfig, GLX_RGBA_TYPE, 0, True); - if(!x11_context->glx_context) { - fprintf(stderr, "mgl error: glXCreateContext failed\n"); - mgl_window_deinit(self); - return -1; - } - - x11_context->color_map = XCreateColormap(context->connection, DefaultRootWindow(context->connection), x11_context->visual_info->visual, AllocNone); + XVisualInfo *visual_info = x11_context_get_xvisual_info(x11_context); + x11_context->color_map = XCreateColormap(context->connection, DefaultRootWindow(context->connection), visual_info->visual, AllocNone); if(!x11_context->color_map) { fprintf(stderr, "mgl error: XCreateColormap failed\n"); mgl_window_deinit(self); @@ -645,7 +883,7 @@ static int mgl_window_init(mgl_window *self, const char *title, const mgl_window } else { self->window = XCreateWindow(context->connection, parent_window, window_pos.x, window_pos.y, window_size.x, window_size.y, 0, - x11_context->visual_info->depth, InputOutput, x11_context->visual_info->visual, + visual_info->depth, InputOutput, visual_info->visual, CWColormap | CWEventMask | CWOverrideRedirect | CWBorderPixel | CWBackPixel | CWBitGravity, &window_attr); if(!self->window) { fprintf(stderr, "mgl error: XCreateWindow failed\n"); @@ -703,15 +941,14 @@ static int mgl_window_init(mgl_window *self, const char *title, const mgl_window XFlush(context->connection); - /* TODO: Check for failure? */ - if(!context->gl.glXMakeContextCurrent(context->connection, self->window, self->window, x11_context->glx_context)) { + if(!x11_context_make_gl_context_current(x11_context, self->window)) { fprintf(stderr, "mgl error: failed to make opengl context current!\n"); mgl_window_deinit(self); return -1; } self->vsync_enabled = true; - set_vertical_sync_enabled(self->window, self->vsync_enabled ? 1 : 0); + set_vertical_sync_enabled(self, self->vsync_enabled ? 1 : 0); context->gl.glEnable(GL_TEXTURE_2D); context->gl.glEnable(GL_BLEND); @@ -1303,7 +1540,7 @@ bool mgl_window_poll_event(mgl_window *self, mgl_event *event) { void mgl_window_display(mgl_window *self) { mgl_context *context = mgl_get_context(); - context->gl.glXSwapBuffers(context->connection, self->window); + x11_context_swap_buffers(self->context, self->window); if(self->low_latency) { context->gl.glFlush(); context->gl.glFinish(); @@ -1441,7 +1678,7 @@ void mgl_window_set_framerate_limit(mgl_window *self, int fps) { void mgl_window_set_vsync_enabled(mgl_window *self, bool enabled) { self->vsync_enabled = enabled; - set_vertical_sync_enabled(self->window, self->vsync_enabled ? 1 : 0); + set_vertical_sync_enabled(self, self->vsync_enabled ? 1 : 0); } bool mgl_window_is_vsync_enabled(const mgl_window *self) { -- cgit v1.2.3