aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-08-04 20:27:26 +0200
committerdec05eba <dec05eba@protonmail.com>2024-08-04 20:27:26 +0200
commite8b1320f91838a29891c6a5b377160e27a0adcf5 (patch)
tree2d68806f424749cecd7af49f5e5471288a876b8f
parent6d4f639c9c0abd3f39e4382f2be3a9d2d56a3104 (diff)
Add option to choose render api (glx or egl) in window creation
-rw-r--r--include/mgl/gl.h37
-rw-r--r--include/mgl/gl_macro.h13
-rw-r--r--include/mgl/window/window.h6
-rw-r--r--src/gl.c142
-rw-r--r--src/window/window.c469
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 <dlfcn.h>
#include <stdio.h>
+#include <string.h>
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) {