aboutsummaryrefslogtreecommitdiff
path: root/src/window/window.c
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 /src/window/window.c
parent6d4f639c9c0abd3f39e4382f2be3a9d2d56a3104 (diff)
Add option to choose render api (glx or egl) in window creation
Diffstat (limited to 'src/window/window.c')
-rw-r--r--src/window/window.c469
1 files changed, 353 insertions, 116 deletions
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) {