diff options
Diffstat (limited to 'src/egl.c')
-rw-r--r-- | src/egl.c | 144 |
1 files changed, 114 insertions, 30 deletions
@@ -1,18 +1,19 @@ #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 <unistd.h> +#include <sys/capability.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: rename gsr_egl to something else since this includes both egl and glx and in the future maybe vulkan too // TODO: Move this shit to a separate wayland file, and have a separate file for x11. @@ -93,7 +94,7 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32 } if(egl->wayland.num_outputs == GSR_MAX_OUTPUTS) { - fprintf(stderr, "gsr warning: reached maximum outputs (32), ignoring output %u\n", name); + fprintf(stderr, "gsr warning: reached maximum outputs (%d), ignoring output %u\n", GSR_MAX_OUTPUTS, name); return; } @@ -134,21 +135,42 @@ static void reset_cap_nice(void) { 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 +static void store_x11_monitor(const gsr_monitor *monitor, void *userdata) { + gsr_egl *egl = userdata; + if(egl->x11.num_outputs == GSR_MAX_OUTPUTS) { + fprintf(stderr, "gsr warning: reached maximum outputs (%d), ignoring output %s\n", GSR_MAX_OUTPUTS, monitor->name); + return; + } + + char *monitor_name = strdup(monitor->name); + if(!monitor_name) + return; + + const int index = egl->x11.num_outputs; + egl->x11.outputs[index].name = monitor_name; + egl->x11.outputs[index].pos = monitor->pos; + egl->x11.outputs[index].size = monitor->size; + egl->x11.outputs[index].connector_id = monitor->connector_id; + egl->x11.outputs[index].rotation = monitor->rotation; + egl->x11.outputs[index].monitor_identifier = monitor->monitor_identifier; + ++egl->x11.num_outputs; +} + +#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_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 @@ -185,6 +207,7 @@ static bool gsr_egl_create_window(gsr_egl *self, bool wayland) { EGLConfig ecfg; int32_t num_config = 0; + // TODO: Use EGL_OPENGL_ES_BIT as amd requires that for external texture, but that breaks software encoding const int32_t attr[] = { EGL_BUFFER_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, @@ -226,6 +249,7 @@ static bool gsr_egl_create_window(gsr_egl *self, bool wayland) { } } + // TODO: Use EGL_OPENGL_ES_API as amd requires that for external texture, but that breaks software encoding self->eglBindAPI(EGL_OPENGL_API); self->egl_display = self->eglGetDisplay(self->wayland.dpy ? (EGLNativeDisplayType)self->wayland.dpy : (EGLNativeDisplayType)self->x11.dpy); @@ -238,12 +262,12 @@ static bool gsr_egl_create_window(gsr_egl *self, bool wayland) { fprintf(stderr, "gsr error: gsr_egl_create_window failed: eglInitialize failed\n"); goto fail; } - + 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; } - + 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"); @@ -251,6 +275,7 @@ static bool gsr_egl_create_window(gsr_egl *self, bool wayland) { } if(wayland) { + // TODO: Error check? 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); @@ -268,6 +293,11 @@ static bool gsr_egl_create_window(gsr_egl *self, bool wayland) { goto fail; } + if(!wayland) { + self->x11.num_outputs = 0; + for_each_active_monitor_output_x11_not_cached(self->x11.dpy, store_x11_monitor, self); + } + reset_cap_nice(); return true; @@ -363,6 +393,17 @@ static bool gsr_egl_proc_load_egl(gsr_egl *self) { self->glEGLImageTargetTexture2DOES = (FUNC_glEGLImageTargetTexture2DOES)self->eglGetProcAddress("glEGLImageTargetTexture2DOES"); self->eglQueryDisplayAttribEXT = (FUNC_eglQueryDisplayAttribEXT)self->eglGetProcAddress("eglQueryDisplayAttribEXT"); self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT"); + self->eglQueryDmaBufModifiersEXT = (FUNC_eglQueryDmaBufModifiersEXT)self->eglGetProcAddress("eglQueryDmaBufModifiersEXT"); + + if(!self->eglExportDMABUFImageQueryMESA) { + fprintf(stderr, "gsr error: gsr_egl_load failed: could not find eglExportDMABUFImageQueryMESA\n"); + return false; + } + + if(!self->eglExportDMABUFImageMESA) { + fprintf(stderr, "gsr error: gsr_egl_load failed: could not find eglExportDMABUFImageMESA\n"); + return false; + } if(!self->glEGLImageTargetTexture2DOES) { fprintf(stderr, "gsr error: gsr_egl_load failed: could not find glEGLImageTargetTexture2DOES\n"); @@ -417,9 +458,7 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) { { (void**)&self->glTexParameteriv, "glTexParameteriv" }, { (void**)&self->glGetTexLevelParameteriv, "glGetTexLevelParameteriv" }, { (void**)&self->glTexImage2D, "glTexImage2D" }, - { (void**)&self->glCopyImageSubData, "glCopyImageSubData" }, { (void**)&self->glGetTexImage, "glGetTexImage" }, - { (void**)&self->glClearTexImage, "glClearTexImage" }, { (void**)&self->glGenFramebuffers, "glGenFramebuffers" }, { (void**)&self->glBindFramebuffer, "glBindFramebuffer" }, { (void**)&self->glDeleteFramebuffers, "glDeleteFramebuffers" }, @@ -460,6 +499,9 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) { { (void**)&self->glUniform2f, "glUniform2f" }, { (void**)&self->glDebugMessageCallback, "glDebugMessageCallback" }, { (void**)&self->glScissor, "glScissor" }, + { (void**)&self->glReadPixels, "glReadPixels" }, + { (void**)&self->glMapBuffer, "glMapBuffer" }, + { (void**)&self->glUnmapBuffer, "glUnmapBuffer" }, { NULL, NULL } }; @@ -503,10 +545,6 @@ bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland, bool is_monitor_cap } 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) { @@ -517,7 +555,8 @@ bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland, bool is_monitor_cap if(!gsr_egl_load_egl(self, self->egl_library)) goto fail; - if(!gsr_egl_load_glx(self, self->glx_library)) + /* In some distros (alpine for example libGLX doesn't exist, but libGL can be used instead) */ + if(!gsr_egl_load_glx(self, self->glx_library ? self->glx_library : self->gl_library)) goto fail; if(!gsr_egl_load_gl(self, self->gl_library)) @@ -588,6 +627,14 @@ void gsr_egl_unload(gsr_egl *self) { self->x11.window = None; } + for(int i = 0; i < self->x11.num_outputs; ++i) { + if(self->x11.outputs[i].name) { + free(self->x11.outputs[i].name); + self->x11.outputs[i].name = NULL; + } + } + self->x11.num_outputs = 0; + if(self->wayland.window) { wl_egl_window_destroy(self->wayland.window); self->wayland.window = NULL; @@ -644,10 +691,47 @@ 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; +bool gsr_egl_process_event(gsr_egl *self) { + switch(gsr_egl_get_display_server(self)) { + case GSR_DISPLAY_SERVER_X11: { + if(XPending(self->x11.dpy)) { + XNextEvent(self->x11.dpy, &self->x11.xev); + return true; + } + return false; + } + case GSR_DISPLAY_SERVER_WAYLAND: { + // TODO: pselect on wl_display_get_fd before doing dispatch + const bool events_available = wl_display_dispatch_pending(self->wayland.dpy) > 0; + wl_display_flush(self->wayland.dpy); + return events_available; + } + } + return false; +} + +void gsr_egl_swap_buffers(gsr_egl *self) { + /* This uses less cpu than swap buffer on nvidia */ + // TODO: Do these and remove swap + //self->glFlush(); + //self->glFinish(); + if(self->egl_display) { + self->eglSwapBuffers(self->egl_display, self->egl_surface); + } else if(self->x11.window) { + self->glXSwapBuffers(self->x11.dpy, self->x11.window); + } +} - // TODO: pselect on wl_display_get_fd before doing dispatch - wl_display_dispatch(self->wayland.dpy); +gsr_display_server gsr_egl_get_display_server(const gsr_egl *self) { + if(self->wayland.dpy) + return GSR_DISPLAY_SERVER_WAYLAND; + else + return GSR_DISPLAY_SERVER_X11; +} + +XEvent* gsr_egl_get_event_data(gsr_egl *self) { + if(gsr_egl_get_display_server(self) == GSR_DISPLAY_SERVER_X11) + return &self->x11.xev; + else + return NULL; } |