From fcd51e7373d14881e13ad086304d3511355b5f1b Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 10 Feb 2024 10:57:33 +0000 Subject: [PATCH 1/4] build: add libepoxy Add libepoxy dependency to CI manifest and Nix. For Nix, we need to set shellHook to workaround a NixOS limitation, see: https://github.com/NixOS/nixpkgs/issues/287763 Signed-off-by: Yuxuan Shui --- .builds/freebsd.yml | 1 + .editorconfig | 3 +++ flake.nix | 18 ++++++++++++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 41c3d927..546df097 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -12,6 +12,7 @@ packages: - uthash - libconfig - libglvnd + - libepoxy - dbus - pcre sources: diff --git a/.editorconfig b/.editorconfig index b40d8e8b..fea97be8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,6 @@ root = true indent_style = tab indent_size = 8 max_line_length = 90 +[*.nix] +indent_style = space +indent_size = 2 diff --git a/flake.nix b/flake.nix index 324498e0..414cacc9 100644 --- a/flake.nix +++ b/flake.nix @@ -24,16 +24,22 @@ overlays = [ overlay ]; in rec { inherit overlay overlays; - defaultPackage = pkgs.picom.overrideAttrs { + defaultPackage = pkgs.picom.overrideAttrs (o: { version = "11"; src = ./.; - }; + buildInputs = o.buildInputs ++ [ pkgs.libepoxy ]; + }); devShell = defaultPackage.overrideAttrs { - buildInputs = defaultPackage.buildInputs ++ [ - pkgs.clang-tools_17 - pkgs.llvmPackages_17.clang-unwrapped.python - ]; + buildInputs = defaultPackage.buildInputs ++ (with pkgs; [ + clang-tools_17 + llvmPackages_17.clang-unwrapped.python + ]); hardeningDisable = [ "fortify" ]; + shellHook = '' + # Workaround a NixOS limitation on sanitizers: + # See: https://github.com/NixOS/nixpkgs/issues/287763 + export LD_LIBRARY_PATH+=":/run/opengl-driver/lib" + ''; }; }); } From eb723eee296e4095cd4f03de5be3ed7048762851 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 10 Feb 2024 20:36:02 +0000 Subject: [PATCH 2/4] backend: gl: use libepoxy There is actually no specification what symbols are exported from a libGL implementation. The (extremely outdated) OpenGL ABI specification says only GL 1.2 functions are guaranteed. Don't know how relevant that is now, but different libGL implementations do export different set of symbols. On Linux we are most likely to be linked with libglvnd, which has everything we need. But on other platforms this is not necessarily the case, for example on OpenBSD we are missing glGetQueryObjectui64v. Use libepoxy so we can outsource this problem and never worry about it ever again. Plus it also saves us from calling GetProcAddress ourselves. Changes other than trivial build fixes I have to make: 1. Can't use eglCreatePlatformWindowSurface/eglGetPlatformDisplay. libepoxy checks for EGL 1.5 when resolving these functions. But without a current context, libepoxy assumes we only have EGL 1.4. This creates a chicken and egg problem - we need a display to call eglGetPlatformDisplay. We have to use the *EXT version instead. Signed-off-by: Yuxuan Shui --- src/backend/gl/egl.c | 64 +++++++------------------------------- src/backend/gl/egl.h | 10 ++---- src/backend/gl/gl_common.c | 3 +- src/backend/gl/gl_common.h | 3 +- src/backend/gl/glx.c | 42 ------------------------- src/backend/gl/glx.h | 27 ++-------------- src/log.c | 29 ++++++----------- src/meson.build | 4 +-- src/opengl.h | 4 +-- src/vblank.c | 9 +----- 10 files changed, 32 insertions(+), 163 deletions(-) diff --git a/src/backend/gl/egl.c b/src/backend/gl/egl.c index ca703591..d0a1ef35 100644 --- a/src/backend/gl/egl.c +++ b/src/backend/gl/egl.c @@ -36,12 +36,6 @@ struct egl_data { EGLContext ctx; }; -static PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC glEGLImageTargetTexStorage = NULL; -static PFNEGLCREATEIMAGEKHRPROC eglCreateImageProc = NULL; -static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageProc = NULL; -static PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplayProc = NULL; -static PFNEGLCREATEPLATFORMWINDOWSURFACEPROC eglCreatePlatformWindowSurfaceProc = NULL; - const char *eglGetErrorString(EGLint error) { #define CASE_STR(value) \ case value: return #value; @@ -74,7 +68,7 @@ static void egl_release_image(backend_t *base, struct gl_texture *tex) { struct egl_pixmap *p = tex->user_data; // Release binding if (p->image != EGL_NO_IMAGE) { - eglDestroyImageProc(gd->display, p->image); + eglDestroyImage(gd->display, p->image); p->image = EGL_NO_IMAGE; } @@ -134,18 +128,6 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) { bool success = false; struct egl_data *gd = NULL; -#define get_proc(name, type) \ - name##Proc = (type)eglGetProcAddress(#name); \ - if (!name##Proc) { \ - log_error("Failed to get EGL function " #name); \ - goto end; \ - } - get_proc(eglCreateImage, PFNEGLCREATEIMAGEKHRPROC); - get_proc(eglDestroyImage, PFNEGLDESTROYIMAGEKHRPROC); - get_proc(eglGetPlatformDisplay, PFNEGLGETPLATFORMDISPLAYPROC); - get_proc(eglCreatePlatformWindowSurface, PFNEGLCREATEPLATFORMWINDOWSURFACEPROC); -#undef get_proc - // Check if we have the X11 platform const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); if (strstr(exts, "EGL_EXT_platform_x11") == NULL) { @@ -154,12 +136,12 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) { } gd = ccalloc(1, struct egl_data); - gd->display = eglGetPlatformDisplayProc(EGL_PLATFORM_X11_EXT, ps->c.dpy, - (EGLAttrib[]){ - EGL_PLATFORM_X11_SCREEN_EXT, - ps->c.screen, - EGL_NONE, - }); + gd->display = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, ps->c.dpy, + (EGLint[]){ + EGL_PLATFORM_X11_SCREEN_EXT, + ps->c.screen, + EGL_NONE, + }); if (gd->display == EGL_NO_DISPLAY) { log_error("Failed to get EGL display."); goto end; @@ -212,7 +194,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) { // clang-format on gd->target_win = - eglCreatePlatformWindowSurfaceProc(gd->display, config, &target, NULL); + eglCreatePlatformWindowSurfaceEXT(gd->display, config, &target, NULL); if (gd->target_win == EGL_NO_SURFACE) { log_error("Failed to create EGL surface."); goto end; @@ -243,14 +225,6 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) { goto end; } - glEGLImageTargetTexStorage = - (PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC)eglGetProcAddress("glEGLImageTargetTexS" - "torageEXT"); - if (glEGLImageTargetTexStorage == NULL) { - log_error("Failed to get glEGLImageTargetTexStorageEXT."); - goto end; - } - gd->gl.decouple_texture_user_data = egl_decouple_user_data; gd->gl.release_user_data = egl_release_image; @@ -302,9 +276,8 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b eglpixmap = cmalloc(struct egl_pixmap); eglpixmap->pixmap = pixmap; - eglpixmap->image = - eglCreateImageProc(gd->display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, - (EGLClientBuffer)(uintptr_t)pixmap, NULL); + eglpixmap->image = eglCreateImage(gd->display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, + (EGLClientBuffer)(uintptr_t)pixmap, NULL); eglpixmap->owned = owned; if (eglpixmap->image == EGL_NO_IMAGE) { @@ -324,14 +297,14 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b wd->dim = 0; wd->inner->refcount = 1; glBindTexture(GL_TEXTURE_2D, inner->texture); - glEGLImageTargetTexStorage(GL_TEXTURE_2D, eglpixmap->image, NULL); + glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, eglpixmap->image, NULL); glBindTexture(GL_TEXTURE_2D, 0); gl_check_err(); return wd; err: if (eglpixmap && eglpixmap->image) { - eglDestroyImageProc(gd->display, eglpixmap->image); + eglDestroyImage(gd->display, eglpixmap->image); } free(eglpixmap); @@ -422,7 +395,6 @@ struct backend_operations egl_ops = { .max_buffer_age = 5, // Why? }; -PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName; /** * Check if a EGL extension exists. */ @@ -472,16 +444,4 @@ void eglext_init(EGLDisplay dpy) { check_ext(EGL_MESA_query_driver); #endif #undef check_ext - - // Checking if the returned function pointer is NULL is not really necessary, - // or maybe not even useful, since eglGetProcAddress might always return - // something. We are doing it just for completeness' sake. - -#ifdef EGL_MESA_query_driver - eglGetDisplayDriverName = - (PFNEGLGETDISPLAYDRIVERNAMEPROC)eglGetProcAddress("eglGetDisplayDriverName"); - if (!eglGetDisplayDriverName) { - eglext.has_EGL_MESA_query_driver = false; - } -#endif } diff --git a/src/backend/gl/egl.h b/src/backend/gl/egl.h index f482032b..033e84da 100644 --- a/src/backend/gl/egl.h +++ b/src/backend/gl/egl.h @@ -1,10 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui #pragma once -#include -#include -#include -#include +#include +#include #include #include #include @@ -24,8 +22,4 @@ struct eglext_info { extern struct eglext_info eglext; -#ifdef EGL_MESA_query_driver -extern PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName; -#endif - void eglext_init(EGLDisplay); diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index badbd9bb..8e1b93df 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui -#include -#include +#include #include #include #include diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index aff0e0bc..8ffec9d2 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui #pragma once -#include -#include +#include #include #include diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 78143a2b..145804c2 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -580,16 +580,6 @@ static inline bool glx_has_extension(Display *dpy, int screen, const char *ext) } struct glxext_info glxext = {0}; -PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI; -PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; -PFNGLXGETSYNCVALUESOMLPROC glXGetSyncValuesOML; -PFNGLXWAITFORMSCOMLPROC glXWaitForMscOML; -PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; -PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI; -PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA; -PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; -PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; -PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB; #ifdef GLX_MESA_query_renderer PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glXQueryCurrentRendererIntegerMESA; @@ -614,36 +604,4 @@ void glxext_init(Display *dpy, int screen) { check_ext(GLX_MESA_query_renderer); #endif #undef check_ext - -#define lookup(name) ((name) = (__typeof__(name))glXGetProcAddress((GLubyte *)#name)) - // Checking if the returned function pointer is NULL is not really necessary, - // or maybe not even useful, since glXGetProcAddress might always return - // something. We are doing it just for completeness' sake. - if (!lookup(glXGetVideoSyncSGI) || !lookup(glXWaitVideoSyncSGI)) { - glxext.has_GLX_SGI_video_sync = false; - } - if (!lookup(glXSwapIntervalEXT)) { - glxext.has_GLX_EXT_swap_control = false; - } - if (!lookup(glXSwapIntervalMESA)) { - glxext.has_GLX_MESA_swap_control = false; - } - if (!lookup(glXSwapIntervalSGI)) { - glxext.has_GLX_SGI_swap_control = false; - } - if (!lookup(glXWaitForMscOML) || !lookup(glXGetSyncValuesOML)) { - glxext.has_GLX_OML_sync_control = false; - } - if (!lookup(glXBindTexImageEXT) || !lookup(glXReleaseTexImageEXT)) { - glxext.has_GLX_EXT_texture_from_pixmap = false; - } - if (!lookup(glXCreateContextAttribsARB)) { - glxext.has_GLX_ARB_create_context = false; - } -#ifdef GLX_MESA_query_renderer - if (!lookup(glXQueryCurrentRendererIntegerMESA)) { - glxext.has_GLX_MESA_query_renderer = false; - } -#endif -#undef lookup } diff --git a/src/backend/gl/glx.h b/src/backend/gl/glx.h index c7ff281c..a7663d94 100644 --- a/src/backend/gl/glx.h +++ b/src/backend/gl/glx.h @@ -1,17 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui #pragma once -#include -// Older version of glx.h defines function prototypes for these extensions... -// Rename them to avoid conflicts -#define glXSwapIntervalMESA glXSwapIntervalMESA_ -#define glXBindTexImageEXT glXBindTexImageEXT_ -#define glXReleaseTexImageEXT glXReleaseTexImageEXT -#include -#undef glXSwapIntervalMESA -#undef glXBindTexImageEXT -#undef glXReleaseTexImageEXT #include +#include +#include #include #include @@ -59,19 +51,4 @@ struct glxext_info { extern struct glxext_info glxext; -extern PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI; -extern PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; -extern PFNGLXGETSYNCVALUESOMLPROC glXGetSyncValuesOML; -extern PFNGLXWAITFORMSCOMLPROC glXWaitForMscOML; -extern PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; -extern PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI; -extern PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA; -extern PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; -extern PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; -extern PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB; - -#ifdef GLX_MESA_query_renderer -extern PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glXQueryCurrentRendererIntegerMESA; -#endif - void glxext_init(Display *, int screen); diff --git a/src/log.c b/src/log.c index 664b9f41..ab7c1699 100644 --- a/src/log.c +++ b/src/log.c @@ -9,7 +9,7 @@ #include #ifdef CONFIG_OPENGL -#include +#include #include "backend/gl/gl_common.h" #include "backend/gl/glx.h" #endif @@ -338,21 +338,14 @@ struct log_target *stderr_logger_new(void) { } #ifdef CONFIG_OPENGL -/// An opengl logger that can be used for logging into opengl debugging tools, -/// such as apitrace -struct gl_string_marker_logger { - struct log_target tgt; - PFNGLSTRINGMARKERGREMEDYPROC gl_string_marker; -}; -static void -gl_string_marker_logger_write(struct log_target *tgt, const char *str, size_t len) { - auto g = (struct gl_string_marker_logger *)tgt; +static void gl_string_marker_logger_write(struct log_target *tgt attr_unused, + const char *str, size_t len) { // strip newlines at the end of the string while (len > 0 && str[len - 1] == '\n') { len--; } - g->gl_string_marker((GLsizei)len, str); + glStringMarkerGREMEDY((GLsizei)len, str); } static const struct log_ops gl_string_marker_logger_ops = { @@ -361,20 +354,16 @@ static const struct log_ops gl_string_marker_logger_ops = { .destroy = logger_trivial_destroy, }; +/// Create an opengl logger that can be used for logging into opengl debugging tools, +/// such as apitrace struct log_target *gl_string_marker_logger_new(void) { if (!gl_has_extension("GL_GREMEDY_string_marker")) { return NULL; } - void *fnptr = glXGetProcAddress((GLubyte *)"glStringMarkerGREMEDY"); - if (!fnptr) { - return NULL; - } - - auto ret = cmalloc(struct gl_string_marker_logger); - ret->tgt.ops = &gl_string_marker_logger_ops; - ret->gl_string_marker = fnptr; - return &ret->tgt; + auto ret = cmalloc(struct log_target); + ret->ops = &gl_string_marker_logger_ops; + return ret; } #else diff --git a/src/meson.build b/src/meson.build index dd10eaec..d7108fba 100644 --- a/src/meson.build +++ b/src/meson.build @@ -58,8 +58,8 @@ if get_option('vsync_drm') endif if get_option('opengl') - cflags += ['-DCONFIG_OPENGL', '-DGL_GLEXT_PROTOTYPES'] - deps += [dependency('gl', required: true), dependency('egl', required: true)] + cflags += ['-DCONFIG_OPENGL'] + deps += [dependency('epoxy', required: true)] srcs += [ 'opengl.c' ] endif diff --git a/src/opengl.h b/src/opengl.h index cd074ff2..6f6da068 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -18,9 +18,9 @@ #include "render.h" #include "win.h" -#include -#include #include +#include +#include #include #include #include diff --git a/src/vblank.c b/src/vblank.c index a9f82116..b9070881 100644 --- a/src/vblank.c +++ b/src/vblank.c @@ -11,11 +11,11 @@ #ifdef CONFIG_OPENGL // Enable sgi_video_sync_vblank_scheduler -#include #include #include #include #include +#include #include #endif @@ -96,8 +96,6 @@ struct sgi_video_sync_thread_args { pthread_cond_t start_cnd; }; -static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; - static bool check_sgi_video_sync_extension(Display *dpy, int screen) { const char *glx_ext = glXQueryExtensionsString(dpy, screen); const char *needle = "GLX_SGI_video_sync"; @@ -112,11 +110,6 @@ static bool check_sgi_video_sync_extension(Display *dpy, int screen) { return false; } - glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC)(void *)glXGetProcAddress( - (const GLubyte *)"glXWaitVideoSyncSGI"); - if (!glXWaitVideoSyncSGI) { - return false; - } return true; } From 755996a42c88483b452e7b9133c8b69c808d3b7a Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 10 Feb 2024 13:28:13 +0000 Subject: [PATCH 3/4] backend: gl: use libepoxy's has_*_extension So we don't need maintain our own version. Signed-off-by: Yuxuan Shui --- src/backend/gl/egl.c | 39 ++++------------------------------ src/backend/gl/gl_common.c | 4 ++-- src/backend/gl/gl_common.h | 20 ------------------ src/backend/gl/glx.c | 43 ++++---------------------------------- src/log.c | 2 +- src/opengl.c | 2 +- 6 files changed, 12 insertions(+), 98 deletions(-) diff --git a/src/backend/gl/egl.c b/src/backend/gl/egl.c index d0a1ef35..9f3f153f 100644 --- a/src/backend/gl/egl.c +++ b/src/backend/gl/egl.c @@ -395,40 +395,6 @@ struct backend_operations egl_ops = { .max_buffer_age = 5, // Why? }; -/** - * Check if a EGL extension exists. - */ -static inline bool egl_has_extension(EGLDisplay dpy, const char *ext) { - const char *egl_exts = eglQueryString(dpy, EGL_EXTENSIONS); - if (!egl_exts) { - log_error("Failed get EGL extension list."); - return false; - } - - auto inlen = strlen(ext); - const char *curr = egl_exts; - bool match = false; - while (curr && !match) { - const char *end = strchr(curr, ' '); - if (!end) { - // Last extension string - match = strcmp(ext, curr) == 0; - } else if (curr + inlen == end) { - // Length match, do match string - match = strncmp(ext, curr, (unsigned long)(end - curr)) == 0; - } - curr = end ? end + 1 : NULL; - } - - if (!match) { - log_info("Missing EGL extension %s.", ext); - } else { - log_info("Found EGL extension %s.", ext); - } - - return match; -} - struct eglext_info eglext = {0}; void eglext_init(EGLDisplay dpy) { @@ -436,7 +402,10 @@ void eglext_init(EGLDisplay dpy) { return; } eglext.initialized = true; -#define check_ext(name) eglext.has_##name = egl_has_extension(dpy, #name) +#define check_ext(name) \ + eglext.has_##name = epoxy_has_egl_extension(dpy, #name); \ + log_info("Extension " #name " - %s", eglext.has_##name ? "present" : "absent") + check_ext(EGL_EXT_buffer_age); check_ext(EGL_EXT_create_context_robustness); check_ext(EGL_KHR_image_pixmap); diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 8e1b93df..2ef41702 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -971,8 +971,8 @@ bool gl_init(struct gl_data *gd, session_t *ps) { } else { gd->is_nvidia = false; } - gd->has_robustness = gl_has_extension("GL_ARB_robustness"); - gd->has_egl_image_storage = gl_has_extension("GL_EXT_EGL_image_storage"); + gd->has_robustness = epoxy_has_gl_extension("GL_ARB_robustness"); + gd->has_egl_image_storage = epoxy_has_gl_extension("GL_EXT_EGL_image_storage"); gl_check_err(); return true; diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index 8ffec9d2..50bec7c6 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -263,26 +263,6 @@ static inline bool gl_check_fb_complete_(const char *func, int line, GLenum fb) #define gl_check_fb_complete(fb) gl_check_fb_complete_(__func__, __LINE__, (fb)) -/** - * Check if a GL extension exists. - */ -static inline bool gl_has_extension(const char *ext) { - int nexts = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &nexts); - for (int i = 0; i < nexts || !nexts; i++) { - const char *exti = (const char *)glGetStringi(GL_EXTENSIONS, (GLuint)i); - if (exti == NULL) { - break; - } - if (strcmp(ext, exti) == 0) { - return true; - } - } - gl_clear_err(); - log_info("Missing GL extension %s.", ext); - return false; -} - static const GLuint vert_coord_loc = 0; static const GLuint vert_in_texcoord_loc = 1; diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 145804c2..af2f891e 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -545,52 +545,17 @@ struct backend_operations glx_ops = { .max_buffer_age = 5, // Why? }; -/** - * Check if a GLX extension exists. - */ -static inline bool glx_has_extension(Display *dpy, int screen, const char *ext) { - const char *glx_exts = glXQueryExtensionsString(dpy, screen); - if (!glx_exts) { - log_error("Failed get GLX extension list."); - return false; - } - - auto inlen = strlen(ext); - const char *curr = glx_exts; - bool match = false; - while (curr && !match) { - const char *end = strchr(curr, ' '); - if (!end) { - // Last extension string - match = strcmp(ext, curr) == 0; - } else if (curr + inlen == end) { - // Length match, do match string - match = strncmp(ext, curr, (unsigned long)(end - curr)) == 0; - } - curr = end ? end + 1 : NULL; - } - - if (!match) { - log_info("Missing GLX extension %s.", ext); - } else { - log_info("Found GLX extension %s.", ext); - } - - return match; -} - struct glxext_info glxext = {0}; -#ifdef GLX_MESA_query_renderer -PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glXQueryCurrentRendererIntegerMESA; -#endif - void glxext_init(Display *dpy, int screen) { if (glxext.initialized) { return; } glxext.initialized = true; -#define check_ext(name) glxext.has_##name = glx_has_extension(dpy, screen, #name) +#define check_ext(name) \ + glxext.has_##name = epoxy_has_glx_extension(dpy, screen, #name); \ + log_info("Extension " #name " - %s", glxext.has_##name ? "present" : "absent") + check_ext(GLX_SGI_video_sync); check_ext(GLX_SGI_swap_control); check_ext(GLX_OML_sync_control); diff --git a/src/log.c b/src/log.c index ab7c1699..4baa7c7b 100644 --- a/src/log.c +++ b/src/log.c @@ -357,7 +357,7 @@ static const struct log_ops gl_string_marker_logger_ops = { /// Create an opengl logger that can be used for logging into opengl debugging tools, /// such as apitrace struct log_target *gl_string_marker_logger_new(void) { - if (!gl_has_extension("GL_GREMEDY_string_marker")) { + if (!epoxy_has_gl_extension("GL_GREMEDY_string_marker")) { return NULL; } diff --git a/src/opengl.c b/src/opengl.c index 7360640c..eb40f1b3 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -181,7 +181,7 @@ bool glx_init(session_t *ps, bool need_render) { // must precede FBConfig fetching if (need_render) { psglx->has_texture_non_power_of_two = - gl_has_extension("GL_ARB_texture_non_power_of_two"); + epoxy_has_gl_extension("GL_ARB_texture_non_power_of_two"); } // Render preparations From 642a43acbb5a92f00c31bd7487c07fab59ab18a9 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 10 Feb 2024 13:31:52 +0000 Subject: [PATCH 4/4] Update README.md and CHANGELOG.md Signed-off-by: Yuxuan Shui --- CHANGELOG.md | 5 +++++ README.md | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1108567..5fbd4471 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,14 @@ * Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170) +## Build changes + +* `picom` now depends on `libepoxy` for OpenGL symbol management. + ## Bug fixes * Workaround a NVIDIA problem that causes high CPU usage after suspend/resume (#1172, #1168) +* Fix building on OpenBSD (#1189, #1188) # v11.1 (2024-Jan-28) diff --git a/README.md b/README.md index d5697238..28790eed 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth * pixman * libdbus (optional, disable with the `-Ddbus=false` meson configure flag) * libconfig (optional, disable with the `-Dconfig_file=false` meson configure flag) -* libGL, libEGL (optional, disable with the `-Dopengl=false` meson configure flag) +* libGL, libEGL, libepoxy (optional, disable with the `-Dopengl=false` meson configure flag) * libpcre2 (optional, disable with the `-Dregex=false` meson configure flag) * libev * uthash @@ -49,13 +49,13 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth On Debian based distributions (e.g. Ubuntu), the needed packages are ``` -libconfig-dev libdbus-1-dev libegl-dev libev-dev libgl-dev libpcre2-dev libpixman-1-dev libx11-xcb-dev libxcb1-dev libxcb-composite0-dev libxcb-damage0-dev libxcb-dpms0-dev libxcb-glx0-dev libxcb-image0-dev libxcb-present-dev libxcb-randr0-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-shape0-dev libxcb-util-dev libxcb-xfixes0-dev libxext-dev meson ninja-build uthash-dev +libconfig-dev libdbus-1-dev libegl-dev libev-dev libgl-dev libepoxy-dev libpcre2-dev libpixman-1-dev libx11-xcb-dev libxcb1-dev libxcb-composite0-dev libxcb-damage0-dev libxcb-dpms0-dev libxcb-glx0-dev libxcb-image0-dev libxcb-present-dev libxcb-randr0-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-shape0-dev libxcb-util-dev libxcb-xfixes0-dev libxext-dev meson ninja-build uthash-dev ``` On Fedora, the needed packages are ``` -dbus-devel gcc git libconfig-devel libdrm-devel libev-devel libX11-devel libX11-xcb libXext-devel libxcb-devel libGL-devel libEGL-devel meson pcre2-devel pixman-devel uthash-devel xcb-util-image-devel xcb-util-renderutil-devel xorg-x11-proto-devel xcb-util-devel +dbus-devel gcc git libconfig-devel libdrm-devel libev-devel libX11-devel libX11-xcb libXext-devel libxcb-devel libGL-devel libEGL-devel libepoxy-devel meson pcre2-devel pixman-devel uthash-devel xcb-util-image-devel xcb-util-renderutil-devel xorg-x11-proto-devel xcb-util-devel ``` To build the documents, you need `asciidoc`