aboutsummaryrefslogtreecommitdiff
path: root/src/egl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl.c')
-rw-r--r--src/egl.c508
1 files changed, 445 insertions, 63 deletions
diff --git a/src/egl.c b/src/egl.c
index a0fcc23..2ad4f85 100644
--- a/src/egl.c
+++ b/src/egl.c
@@ -1,84 +1,329 @@
#include "../include/egl.h"
#include "../include/library_loader.h"
+#include "../include/utils.h"
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <dlfcn.h>
+#include <assert.h>
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+#include <unistd.h>
+#include <sys/capability.h>
+
+// TODO: rename gsr_egl to something else since this includes both egl and eglx and in the future maybe vulkan too
+
+// TODO: Move this shit to a separate wayland file, and have a separate file for x11.
+
+static void output_handle_geometry(void *data, struct wl_output *wl_output,
+ int32_t x, int32_t y, int32_t phys_width, int32_t phys_height,
+ int32_t subpixel, const char *make, const char *model,
+ int32_t transform) {
+ (void)wl_output;
+ (void)phys_width;
+ (void)phys_height;
+ (void)subpixel;
+ (void)make;
+ (void)model;
+ gsr_wayland_output *gsr_output = data;
+ gsr_output->pos.x = x;
+ gsr_output->pos.y = y;
+ gsr_output->transform = transform;
+}
+
+static void output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
+ (void)wl_output;
+ (void)flags;
+ (void)refresh;
+ gsr_wayland_output *gsr_output = data;
+ gsr_output->size.x = width;
+ gsr_output->size.y = height;
+}
+
+static void output_handle_done(void *data, struct wl_output *wl_output) {
+ (void)data;
+ (void)wl_output;
+}
+
+static void output_handle_scale(void* data, struct wl_output *wl_output, int32_t factor) {
+ (void)data;
+ (void)wl_output;
+ (void)factor;
+}
+
+static void output_handle_name(void *data, struct wl_output *wl_output, const char *name) {
+ (void)wl_output;
+ gsr_wayland_output *gsr_output = data;
+ if(gsr_output->name) {
+ free(gsr_output->name);
+ gsr_output->name = NULL;
+ }
+ gsr_output->name = strdup(name);
+}
+
+static void output_handle_description(void *data, struct wl_output *wl_output, const char *description) {
+ (void)data;
+ (void)wl_output;
+ (void)description;
+}
+
+static const struct wl_output_listener output_listener = {
+ .geometry = output_handle_geometry,
+ .mode = output_handle_mode,
+ .done = output_handle_done,
+ .scale = output_handle_scale,
+ .name = output_handle_name,
+ .description = output_handle_description,
+};
+
+static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
+ (void)version;
+ gsr_egl *egl = data;
+ if (strcmp(interface, "wl_compositor") == 0) {
+ if(egl->wayland.compositor) {
+ wl_compositor_destroy(egl->wayland.compositor);
+ egl->wayland.compositor = NULL;
+ }
+ egl->wayland.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ } else if(strcmp(interface, wl_output_interface.name) == 0) {
+ if(version < 4) {
+ fprintf(stderr, "gsr warning: wl output interface version is < 4, expected >= 4 to capture a monitor. Using KMS capture instead\n");
+ return;
+ }
+
+ if(egl->wayland.num_outputs == GSR_MAX_OUTPUTS) {
+ fprintf(stderr, "gsr warning: reached maximum outputs (32), ignoring output %u\n", name);
+ return;
+ }
+
+ gsr_wayland_output *gsr_output = &egl->wayland.outputs[egl->wayland.num_outputs];
+ egl->wayland.num_outputs++;
+ *gsr_output = (gsr_wayland_output) {
+ .wl_name = name,
+ .output = wl_registry_bind(registry, name, &wl_output_interface, 4),
+ .pos = { .x = 0, .y = 0 },
+ .size = { .x = 0, .y = 0 },
+ .transform = 0,
+ .name = NULL,
+ };
+ wl_output_add_listener(gsr_output->output, &output_listener, gsr_output);
+ }
+}
-static bool gsr_egl_create_window(gsr_egl *self) {
+static void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name) {
+ (void)data;
+ (void)registry;
+ (void)name;
+}
+
+static struct wl_registry_listener registry_listener = {
+ .global = registry_add_object,
+ .global_remove = registry_remove_object,
+};
+
+static void reset_cap_nice(void) {
+ cap_t caps = cap_get_proc();
+ if(!caps)
+ return;
+
+ const cap_value_t cap_to_remove = CAP_SYS_NICE;
+ cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_to_remove, CAP_CLEAR);
+ cap_set_flag(caps, CAP_PERMITTED, 1, &cap_to_remove, CAP_CLEAR);
+ cap_set_proc(caps);
+ cap_free(caps);
+}
+
+#define GLX_DRAWABLE_TYPE 0x8010
+#define GLX_RENDER_TYPE 0x8011
+#define GLX_RGBA_BIT 0x00000001
+#define GLX_WINDOW_BIT 0x00000001
+#define GLX_PIXMAP_BIT 0x00000002
+#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
+#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
+#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
+#define GLX_DOUBLEBUFFER 5
+#define GLX_RED_SIZE 8
+#define GLX_GREEN_SIZE 9
+#define GLX_BLUE_SIZE 10
+#define GLX_ALPHA_SIZE 11
+#define GLX_DEPTH_SIZE 12
+#define GLX_RGBA_TYPE 0x8014
+
+#define GLX_CONTEXT_PRIORITY_LEVEL_EXT 0x3100
+#define GLX_CONTEXT_PRIORITY_HIGH_EXT 0x3101
+#define GLX_CONTEXT_PRIORITY_MEDIUM_EXT 0x3102
+#define GLX_CONTEXT_PRIORITY_LOW_EXT 0x3103
+
+static GLXFBConfig glx_fb_config_choose(gsr_egl *self) {
+ const int glx_visual_attribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ // TODO:
+ //GLX_BIND_TO_TEXTURE_RGBA_EXT, 1,
+ //GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ GLX_DOUBLEBUFFER, True,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 0,
+ GLX_DEPTH_SIZE, 0,
+ None, None
+ };
+
+ // TODO: Cleanup
+ int c = 0;
+ GLXFBConfig *fb_configs = self->glXChooseFBConfig(self->x11.dpy, DefaultScreen(self->x11.dpy), glx_visual_attribs, &c);
+ if(c == 0 || !fb_configs)
+ return NULL;
+
+ return fb_configs[0];
+}
+
+// TODO: Create egl context without surface (in other words, x11/wayland agnostic, doesn't require x11/wayland dependency)
+static bool gsr_egl_create_window(gsr_egl *self, bool wayland) {
EGLConfig ecfg;
int32_t num_config = 0;
- EGLDisplay egl_display = NULL;
- EGLSurface egl_surface = NULL;
- EGLContext egl_context = NULL;
- Window window = None;
-
- int32_t attr[] = {
+
+ const int32_t attr[] = {
EGL_BUFFER_SIZE, 24,
- EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT,
- EGL_NONE
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_NONE, EGL_NONE
};
- int32_t ctxattr[] = {
+ const int32_t ctxattr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
+ EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, /* requires cap_sys_nice, ignored otherwise */
+ EGL_NONE, EGL_NONE
};
- window = XCreateWindow(self->dpy, DefaultRootWindow(self->dpy), 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
-
- if(!window) {
- fprintf(stderr, "gsr error: gsr_gl_create_window failed: failed to create gl window\n");
- goto fail;
+ if(wayland) {
+ self->wayland.dpy = wl_display_connect(NULL);
+ if(!self->wayland.dpy) {
+ fprintf(stderr, "gsr error: gsr_egl_create_window failed: wl_display_connect failed\n");
+ goto fail;
+ }
+
+ self->wayland.registry = wl_display_get_registry(self->wayland.dpy); // TODO: Error checking
+ wl_registry_add_listener(self->wayland.registry, &registry_listener, self); // TODO: Error checking
+
+ // Fetch globals
+ wl_display_roundtrip(self->wayland.dpy);
+
+ // Fetch wl_output
+ wl_display_roundtrip(self->wayland.dpy);
+
+ if(!self->wayland.compositor) {
+ fprintf(stderr, "gsr error: gsr_gl_create_window failed: failed to find compositor\n");
+ goto fail;
+ }
+ } else {
+ self->x11.window = XCreateWindow(self->x11.dpy, DefaultRootWindow(self->x11.dpy), 0, 0, 16, 16, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
+
+ if(!self->x11.window) {
+ fprintf(stderr, "gsr error: gsr_gl_create_window failed: failed to create gl window\n");
+ goto fail;
+ }
}
- egl_display = self->eglGetDisplay(self->dpy);
- if(!egl_display) {
+ self->eglBindAPI(EGL_OPENGL_API);
+
+ self->egl_display = self->eglGetDisplay(self->wayland.dpy ? (EGLNativeDisplayType)self->wayland.dpy : (EGLNativeDisplayType)self->x11.dpy);
+ if(!self->egl_display) {
fprintf(stderr, "gsr error: gsr_egl_create_window failed: eglGetDisplay failed\n");
goto fail;
}
- if(!self->eglInitialize(egl_display, NULL, NULL)) {
+ if(!self->eglInitialize(self->egl_display, NULL, NULL)) {
fprintf(stderr, "gsr error: gsr_egl_create_window failed: eglInitialize failed\n");
goto fail;
}
- if(!self->eglChooseConfig(egl_display, attr, &ecfg, 1, &num_config) || num_config != 1) {
+ if(!self->eglChooseConfig(self->egl_display, attr, &ecfg, 1, &num_config) || num_config != 1) {
fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to find a matching config\n");
goto fail;
}
- egl_surface = self->eglCreateWindowSurface(egl_display, ecfg, (EGLNativeWindowType)window, NULL);
- if(!egl_surface) {
+ self->egl_context = self->eglCreateContext(self->egl_display, ecfg, NULL, ctxattr);
+ if(!self->egl_context) {
+ fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to create egl context\n");
+ goto fail;
+ }
+
+ if(wayland) {
+ self->wayland.surface = wl_compositor_create_surface(self->wayland.compositor);
+ self->wayland.window = wl_egl_window_create(self->wayland.surface, 16, 16);
+ self->egl_surface = self->eglCreateWindowSurface(self->egl_display, ecfg, (EGLNativeWindowType)self->wayland.window, NULL);
+ } else {
+ self->egl_surface = self->eglCreateWindowSurface(self->egl_display, ecfg, (EGLNativeWindowType)self->x11.window, NULL);
+ }
+
+ if(!self->egl_surface) {
fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to create window surface\n");
goto fail;
}
-
- egl_context = self->eglCreateContext(egl_display, ecfg, NULL, ctxattr);
- if(!egl_context) {
- fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to create egl context\n");
+
+ if(!self->eglMakeCurrent(self->egl_display, self->egl_surface, self->egl_surface, self->egl_context)) {
+ fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to make egl context current\n");
goto fail;
}
- if(!self->eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)) {
- fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to make context current\n");
+ reset_cap_nice();
+ return true;
+
+ fail:
+ reset_cap_nice();
+ gsr_egl_unload(self);
+ return false;
+}
+
+static bool gsr_egl_switch_to_glx_context(gsr_egl *self) {
+ // TODO: Cleanup
+
+ if(self->egl_context) {
+ self->eglMakeCurrent(self->egl_display, NULL, NULL, NULL);
+ self->eglDestroyContext(self->egl_display, self->egl_context);
+ self->egl_context = NULL;
+ }
+
+ if(self->egl_surface) {
+ self->eglDestroySurface(self->egl_display, self->egl_surface);
+ self->egl_surface = NULL;
+ }
+
+ if(self->egl_display) {
+ self->eglTerminate(self->egl_display);
+ self->egl_display = NULL;
+ }
+
+ self->glx_fb_config = glx_fb_config_choose(self);
+ if(!self->glx_fb_config) {
+ fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to find a suitable fb config\n");
+ goto fail;
+ }
+
+ // TODO:
+ //self->glx_context = self->glXCreateContextAttribsARB(self->x11.dpy, self->glx_fb_config, NULL, True, context_attrib_list);
+ self->glx_context = self->glXCreateNewContext(self->x11.dpy, self->glx_fb_config, GLX_RGBA_TYPE, NULL, True);
+ if(!self->glx_context) {
+ fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to create glx context\n");
+ goto fail;
+ }
+
+ if(!self->glXMakeContextCurrent(self->x11.dpy, self->x11.window, self->x11.window, self->glx_context)) {
+ fprintf(stderr, "gsr error: gsr_egl_create_window failed: failed to make glx context current\n");
goto fail;
}
- self->egl_display = egl_display;
- self->egl_surface = egl_surface;
- self->egl_context = egl_context;
- self->window = window;
return true;
fail:
- if(egl_context)
- self->eglDestroyContext(egl_display, egl_context);
- if(egl_surface)
- self->eglDestroySurface(egl_display, egl_surface);
- if(egl_display)
- self->eglTerminate(egl_display);
- if(window)
- XDestroyWindow(self->dpy, window);
+ if(self->glx_context) {
+ self->glXMakeContextCurrent(self->x11.dpy, None, None, NULL);
+ self->glXDestroyContext(self->x11.dpy, self->glx_context);
+ self->glx_context = NULL;
+ self->glx_fb_config = NULL;
+ }
return false;
}
@@ -98,6 +343,7 @@ static bool gsr_egl_load_egl(gsr_egl *self, void *library) {
{ (void**)&self->eglDestroyImage, "eglDestroyImage" },
{ (void**)&self->eglSwapInterval, "eglSwapInterval" },
{ (void**)&self->eglSwapBuffers, "eglSwapBuffers" },
+ { (void**)&self->eglBindAPI, "eglBindAPI" },
{ (void**)&self->eglGetProcAddress, "eglGetProcAddress" },
{ NULL, NULL }
@@ -115,6 +361,8 @@ static bool gsr_egl_proc_load_egl(gsr_egl *self) {
self->eglExportDMABUFImageQueryMESA = (FUNC_eglExportDMABUFImageQueryMESA)self->eglGetProcAddress("eglExportDMABUFImageQueryMESA");
self->eglExportDMABUFImageMESA = (FUNC_eglExportDMABUFImageMESA)self->eglGetProcAddress("eglExportDMABUFImageMESA");
self->glEGLImageTargetTexture2DOES = (FUNC_glEGLImageTargetTexture2DOES)self->eglGetProcAddress("glEGLImageTargetTexture2DOES");
+ self->eglQueryDisplayAttribEXT = (FUNC_eglQueryDisplayAttribEXT)self->eglGetProcAddress("eglQueryDisplayAttribEXT");
+ self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT");
if(!self->glEGLImageTargetTexture2DOES) {
fprintf(stderr, "gsr error: gsr_egl_load failed: could not find glEGLImageTargetTexture2DOES\n");
@@ -124,16 +372,49 @@ static bool gsr_egl_proc_load_egl(gsr_egl *self) {
return true;
}
+static bool gsr_egl_load_glx(gsr_egl *self, void *library) {
+ dlsym_assign required_dlsym[] = {
+ { (void**)&self->glXGetProcAddress, "glXGetProcAddress" },
+ { (void**)&self->glXChooseFBConfig, "glXChooseFBConfig" },
+ { (void**)&self->glXMakeContextCurrent, "glXMakeContextCurrent" },
+ { (void**)&self->glXCreateNewContext, "glXCreateNewContext" },
+ { (void**)&self->glXDestroyContext, "glXDestroyContext" },
+ { (void**)&self->glXSwapBuffers, "glXSwapBuffers" },
+
+ { NULL, NULL }
+ };
+
+ if(!dlsym_load_list(library, required_dlsym)) {
+ fprintf(stderr, "gsr error: gsr_egl_load failed: missing required symbols in libGLX.so.0\n");
+ return false;
+ }
+
+ self->glXCreateContextAttribsARB = (FUNC_glXCreateContextAttribsARB)self->glXGetProcAddress((const unsigned char*)"glXCreateContextAttribsARB");
+ if(!self->glXCreateContextAttribsARB) {
+ fprintf(stderr, "gsr error: gsr_egl_load_glx failed: could not find glXCreateContextAttribsARB\n");
+ return false;
+ }
+
+ 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 true;
+}
+
static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
dlsym_assign required_dlsym[] = {
{ (void**)&self->glGetError, "glGetError" },
{ (void**)&self->glGetString, "glGetString" },
+ { (void**)&self->glFlush, "glFlush" },
+ { (void**)&self->glFinish, "glFinish" },
{ (void**)&self->glClear, "glClear" },
{ (void**)&self->glClearColor, "glClearColor" },
{ (void**)&self->glGenTextures, "glGenTextures" },
{ (void**)&self->glDeleteTextures, "glDeleteTextures" },
{ (void**)&self->glBindTexture, "glBindTexture" },
{ (void**)&self->glTexParameteri, "glTexParameteri" },
+ { (void**)&self->glTexParameteriv, "glTexParameteriv" },
{ (void**)&self->glGetTexLevelParameteriv, "glGetTexLevelParameteriv" },
{ (void**)&self->glTexImage2D, "glTexImage2D" },
{ (void**)&self->glCopyImageSubData, "glCopyImageSubData" },
@@ -174,6 +455,8 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glBlendFunc, "glBlendFunc" },
{ (void**)&self->glGetUniformLocation, "glGetUniformLocation" },
{ (void**)&self->glUniform1f, "glUniform1f" },
+ { (void**)&self->glUniform2f, "glUniform2f" },
+ { (void**)&self->glDebugMessageCallback, "glDebugMessageCallback" },
{ NULL, NULL }
};
@@ -186,56 +469,97 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
return true;
}
-bool gsr_egl_load(gsr_egl *self, Display *dpy) {
+// #define GL_DEBUG_TYPE_ERROR 0x824C
+// static void debug_callback( unsigned int source,
+// unsigned int type,
+// unsigned int id,
+// unsigned int severity,
+// int length,
+// const char* message,
+// const void* userParam )
+// {
+// (void)source;
+// (void)id;
+// (void)length;
+// (void)userParam;
+// fprintf( stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
+// ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
+// type, severity, message );
+// }
+
+bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland, bool is_monitor_capture) {
+ (void)is_monitor_capture;
memset(self, 0, sizeof(gsr_egl));
- self->dpy = dpy;
-
- void *egl_lib = NULL;
- void *gl_lib = NULL;
+ self->x11.dpy = dpy;
+ self->context_type = GSR_GL_CONTEXT_TYPE_EGL;
dlerror(); /* clear */
- egl_lib = dlopen("libEGL.so.1", RTLD_LAZY);
- if(!egl_lib) {
+ self->egl_library = dlopen("libEGL.so.1", RTLD_LAZY);
+ if(!self->egl_library) {
fprintf(stderr, "gsr error: gsr_egl_load: failed to load libEGL.so.1, error: %s\n", dlerror());
goto fail;
}
- gl_lib = dlopen("libGL.so.1", RTLD_LAZY);
- if(!egl_lib) {
+ self->glx_library = dlopen("libGLX.so.0", RTLD_LAZY);
+ if(!self->glx_library) {
+ fprintf(stderr, "gsr error: gsr_egl_load: failed to load libGLX.so.0, error: %s\n", dlerror());
+ goto fail;
+ }
+
+ self->gl_library = dlopen("libGL.so.1", RTLD_LAZY);
+ if(!self->egl_library) {
fprintf(stderr, "gsr error: gsr_egl_load: failed to load libGL.so.1, error: %s\n", dlerror());
goto fail;
}
- if(!gsr_egl_load_egl(self, egl_lib))
+ if(!gsr_egl_load_egl(self, self->egl_library))
+ goto fail;
+
+ if(!gsr_egl_load_glx(self, self->glx_library))
goto fail;
- if(!gsr_egl_load_gl(self, gl_lib))
+ if(!gsr_egl_load_gl(self, self->gl_library))
goto fail;
if(!gsr_egl_proc_load_egl(self))
goto fail;
- if(!gsr_egl_create_window(self))
+ if(!gsr_egl_create_window(self, wayland))
+ goto fail;
+
+ if(!gl_get_gpu_info(self, &self->gpu_info))
goto fail;
+ if(self->eglQueryDisplayAttribEXT && self->eglQueryDeviceStringEXT) {
+ intptr_t device = 0;
+ if(self->eglQueryDisplayAttribEXT(self->egl_display, EGL_DEVICE_EXT, &device) && device)
+ self->dri_card_path = self->eglQueryDeviceStringEXT((void*)device, EGL_DRM_DEVICE_FILE_EXT);
+ }
+
+ /* Nvfbc requires glx */
+ if(!wayland && is_monitor_capture && self->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA) {
+ self->context_type = GSR_GL_CONTEXT_TYPE_GLX;
+ self->dri_card_path = NULL;
+ if(!gsr_egl_switch_to_glx_context(self))
+ goto fail;
+ }
+
self->glEnable(GL_BLEND);
self->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- self->egl_library = egl_lib;
- self->gl_library = gl_lib;
+ //self->glEnable(GL_DEBUG_OUTPUT);
+ //self->glDebugMessageCallback(debug_callback, NULL);
+
return true;
fail:
- if(egl_lib)
- dlclose(egl_lib);
- if(gl_lib)
- dlclose(gl_lib);
- memset(self, 0, sizeof(gsr_egl));
+ gsr_egl_unload(self);
return false;
}
void gsr_egl_unload(gsr_egl *self) {
if(self->egl_context) {
+ self->eglMakeCurrent(self->egl_display, NULL, NULL, NULL);
self->eglDestroyContext(self->egl_display, self->egl_context);
self->egl_context = NULL;
}
@@ -250,9 +574,54 @@ void gsr_egl_unload(gsr_egl *self) {
self->egl_display = NULL;
}
- if(self->window) {
- XDestroyWindow(self->dpy, self->window);
- self->window = None;
+ if(self->glx_context) {
+ self->glXMakeContextCurrent(self->x11.dpy, None, None, NULL);
+ self->glXDestroyContext(self->x11.dpy, self->glx_context);
+ self->glx_context = NULL;
+ self->glx_fb_config = NULL;
+ }
+
+ if(self->x11.window) {
+ XDestroyWindow(self->x11.dpy, self->x11.window);
+ self->x11.window = None;
+ }
+
+ if(self->wayland.window) {
+ wl_egl_window_destroy(self->wayland.window);
+ self->wayland.window = NULL;
+ }
+
+ if(self->wayland.surface) {
+ wl_surface_destroy(self->wayland.surface);
+ self->wayland.surface = NULL;
+ }
+
+ for(int i = 0; i < self->wayland.num_outputs; ++i) {
+ if(self->wayland.outputs[i].output) {
+ wl_output_destroy(self->wayland.outputs[i].output);
+ self->wayland.outputs[i].output = NULL;
+ }
+
+ if(self->wayland.outputs[i].name) {
+ free(self->wayland.outputs[i].name);
+ self->wayland.outputs[i].name = NULL;
+ }
+ }
+ self->wayland.num_outputs = 0;
+
+ if(self->wayland.compositor) {
+ wl_compositor_destroy(self->wayland.compositor);
+ self->wayland.compositor = NULL;
+ }
+
+ if(self->wayland.registry) {
+ wl_registry_destroy(self->wayland.registry);
+ self->wayland.registry = NULL;
+ }
+
+ if(self->wayland.dpy) {
+ wl_display_disconnect(self->wayland.dpy);
+ self->wayland.dpy = NULL;
}
if(self->egl_library) {
@@ -260,6 +629,11 @@ void gsr_egl_unload(gsr_egl *self) {
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;
@@ -267,3 +641,11 @@ void gsr_egl_unload(gsr_egl *self) {
memset(self, 0, sizeof(gsr_egl));
}
+
+void gsr_egl_update(gsr_egl *self) {
+ if(!self->wayland.dpy)
+ return;
+
+ // TODO: pselect on wl_display_get_fd before doing dispatch
+ wl_display_dispatch(self->wayland.dpy);
+}