From 7e9d1c6442f858261f27f4b2607d6d8effd14bf1 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 8 Feb 2019 23:57:14 +0000 Subject: [PATCH] Condense GLX extension lookup Put them all into one function, and move the function pointers out of glx_session_t, making them global variables (because them don't change after initialized). Remove the function pointer typedefs and replace them with the ones in glxext.h We also only lookup the functions once per a lifetime of compton. Signed-off-by: Yuxuan Shui --- src/backend/gl/glx.c | 86 +++++++++++++++++++++++++++++++++++++++++++- src/backend/gl/glx.h | 52 ++++++++++++--------------- src/common.h | 28 --------------- src/opengl.c | 20 +++-------- src/render.c | 3 ++ src/vsync.c | 84 +++++++++++-------------------------------- 6 files changed, 134 insertions(+), 139 deletions(-) diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 51a82b2..e826273 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -265,7 +265,7 @@ static void *glx_init(session_t *ps) { } // Ensure GLX_EXT_texture_from_pixmap exists - if (!glx_has_extension(ps->dpy, ps->scr, "GLX_EXT_texture_from_pixmap")) + if (!glxext.has_GLX_EXT_texture_from_pixmap) goto end; // Initialize GLX data structure @@ -542,3 +542,87 @@ backend_info_t glx_backend = { .buffer_age = glx_buffer_age, .max_buffer_age = 5, // XXX 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; + } + + long 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 (end - curr == inlen) { + // Length match, do match string + match = strncmp(ext, curr, 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}; +PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI; +PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; +PFNGLXGETSYNCVALUESOMLPROC glXGetSyncValuesOML; +PFNGLXWAITFORMSCOMLPROC glXWaitForMscOML; +PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; +PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI; +PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA; +PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; +PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; + +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) + check_ext(GLX_SGI_video_sync); + check_ext(GLX_SGI_swap_control); + check_ext(GLX_OML_sync_control); + check_ext(GLX_MESA_swap_control); + check_ext(GLX_EXT_swap_control); + check_ext(GLX_EXT_texture_from_pixmap); +#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; + } +#undef lookup +} diff --git a/src/backend/gl/glx.h b/src/backend/gl/glx.h index 4ffc3a1..0c2bb7a 100644 --- a/src/backend/gl/glx.h +++ b/src/backend/gl/glx.h @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui #pragma once +#include #include +#include #include #include #include @@ -64,36 +66,26 @@ x_visual_to_fbconfig_criteria(xcb_connection_t *c, xcb_visualid_t visual) { }; } -/** - * 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; - } +struct glxext_info { + bool initialized; + bool has_GLX_SGI_video_sync; + bool has_GLX_SGI_swap_control; + bool has_GLX_OML_sync_control; + bool has_GLX_MESA_swap_control; + bool has_GLX_EXT_swap_control; + bool has_GLX_EXT_texture_from_pixmap; +}; - long 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 (end - curr == inlen) { - // Length match, do match string - match = strncmp(ext, curr, end - curr) == 0; - } - curr = end ? end + 1 : NULL; - } +extern struct glxext_info glxext; - if (!match) { - log_info("Missing GLX extension %s.", ext); - } else { - log_info("Found GLX extension %s.", ext); - } +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; - return match; -} +void glxext_init(Display *, int screen); diff --git a/src/common.h b/src/common.h index d5abd80..0dd4d5e 100644 --- a/src/common.h +++ b/src/common.h @@ -189,18 +189,6 @@ typedef void (*GLDEBUGPROC) (GLenum source, GLenum type, typedef void (*f_DebugMessageCallback) (GLDEBUGPROC, void *userParam); #endif -typedef int (*f_WaitVideoSync) (int, int, unsigned *); -typedef int (*f_GetVideoSync) (unsigned *); - -typedef Bool (*f_GetSyncValuesOML) (Display* dpy, GLXDrawable drawable, int64_t* ust, int64_t* msc, int64_t* sbc); -typedef Bool (*f_WaitForMscOML) (Display* dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t* ust, int64_t* msc, int64_t* sbc); - -typedef int (*f_SwapIntervalSGI) (int interval); -typedef int (*f_SwapIntervalMESA) (unsigned int interval); - -typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list); -typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer); - #ifdef CONFIG_OPENGL typedef GLsync (*f_FenceSync) (GLenum condition, GLbitfield flags); typedef GLboolean (*f_IsSync) (GLsync sync); @@ -279,22 +267,6 @@ typedef struct { GLXContext context; /// Whether we have GL_ARB_texture_non_power_of_two. bool has_texture_non_power_of_two; - /// Pointer to glXGetVideoSyncSGI function. - f_GetVideoSync glXGetVideoSyncSGI; - /// Pointer to glXWaitVideoSyncSGI function. - f_WaitVideoSync glXWaitVideoSyncSGI; - /// Pointer to glXGetSyncValuesOML function. - f_GetSyncValuesOML glXGetSyncValuesOML; - /// Pointer to glXWaitForMscOML function. - f_WaitForMscOML glXWaitForMscOML; - /// Pointer to glXSwapIntervalSGI function. - f_SwapIntervalSGI glXSwapIntervalProc; - /// Pointer to glXSwapIntervalMESA function. - f_SwapIntervalMESA glXSwapIntervalMESAProc; - /// Pointer to glXBindTexImageEXT function. - f_BindTexImageEXT glXBindTexImageProc; - /// Pointer to glXReleaseTexImageEXT function. - f_ReleaseTexImageEXT glXReleaseTexImageProc; /// Pointer to the glFenceSync() function. f_FenceSync glFenceSyncProc; /// Pointer to the glIsSync() function. diff --git a/src/opengl.c b/src/opengl.c index b22de44..c129d67 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -83,7 +83,7 @@ glx_init(session_t *ps, bool need_render) { } // Ensure GLX_EXT_texture_from_pixmap exists - if (need_render && !glx_has_extension(ps->dpy, ps->scr, "GLX_EXT_texture_from_pixmap")) + if (need_render && !glxext.has_GLX_EXT_texture_from_pixmap) goto glx_init_end; // Initialize GLX data structure @@ -175,18 +175,6 @@ glx_init(session_t *ps, bool need_render) { psglx->has_texture_non_power_of_two = gl_has_extension( "GL_ARB_texture_non_power_of_two"); - // Acquire function addresses - if (need_render) { - psglx->glXBindTexImageProc = (f_BindTexImageEXT) - glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT"); - psglx->glXReleaseTexImageProc = (f_ReleaseTexImageEXT) - glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT"); - if (!psglx->glXBindTexImageProc || !psglx->glXReleaseTexImageProc) { - log_error("Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT()."); - goto glx_init_end; - } - } - // Render preparations if (need_render) { glx_on_root_change(ps); @@ -626,9 +614,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, // The specification requires rebinding whenever the content changes... // We can't follow this, too slow. if (need_release) - ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); + glXReleaseTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - ps->psglx->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); + glXBindTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); // Cleanup glBindTexture(ptex->target, 0); @@ -647,7 +635,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { // Release binding if (ptex->glpixmap && ptex->texture) { glBindTexture(ptex->target, ptex->texture); - ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); + glXReleaseTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); glBindTexture(ptex->target, 0); } diff --git a/src/render.c b/src/render.c index 6a0de88..caca172 100644 --- a/src/render.c +++ b/src/render.c @@ -1121,6 +1121,9 @@ static bool init_alpha_picts(session_t *ps) { bool init_render(session_t *ps) { // Initialize OpenGL as early as possible +#ifdef CONFIG_OPENGL + glxext_init(ps->dpy, ps->scr); +#endif if (bkend_use_glx(ps)) { #ifdef CONFIG_OPENGL if (!glx_init(ps, true)) diff --git a/src/vsync.c b/src/vsync.c index db5d289..d872f7b 100644 --- a/src/vsync.c +++ b/src/vsync.c @@ -90,24 +90,7 @@ vsync_opengl_init(session_t *ps) { if (!ensure_glx_context(ps)) return false; - if (!glx_has_extension(ps->dpy, ps->scr, "GLX_SGI_video_sync")) { - log_error("Your driver doesn't support SGI_video_sync, giving up."); - return false; - } - - // Get video sync functions - if (!ps->psglx->glXGetVideoSyncSGI) - ps->psglx->glXGetVideoSyncSGI = (f_GetVideoSync) - glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI"); - if (!ps->psglx->glXWaitVideoSyncSGI) - ps->psglx->glXWaitVideoSyncSGI = (f_WaitVideoSync) - glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI"); - if (!ps->psglx->glXWaitVideoSyncSGI || !ps->psglx->glXGetVideoSyncSGI) { - log_error("Failed to get glXWait/GetVideoSyncSGI function."); - return false; - } - - return true; + return glxext.has_GLX_SGI_video_sync; #else log_error("compton is not compiled with OpenGL VSync support."); return false; @@ -120,59 +103,32 @@ vsync_opengl_oml_init(session_t *ps) { if (!ensure_glx_context(ps)) return false; - if (!glx_has_extension(ps->dpy, ps->scr, "GLX_OML_sync_control")) { - log_error("Your driver doesn't support OML_sync_control, giving up."); - return false; - } - - // Get video sync functions - if (!ps->psglx->glXGetSyncValuesOML) - ps->psglx->glXGetSyncValuesOML = (f_GetSyncValuesOML) - glXGetProcAddress ((const GLubyte *) "glXGetSyncValuesOML"); - if (!ps->psglx->glXWaitForMscOML) - ps->psglx->glXWaitForMscOML = (f_WaitForMscOML) - glXGetProcAddress ((const GLubyte *) "glXWaitForMscOML"); - if (!ps->psglx->glXGetSyncValuesOML || !ps->psglx->glXWaitForMscOML) { - log_error("Failed to get OML_sync_control functions."); - return false; - } - - return true; + return glxext.has_GLX_OML_sync_control; #else log_error("compton is not compiled with OpenGL VSync support."); return false; #endif } -static bool -vsync_opengl_swc_swap_interval(session_t *ps, unsigned int interval) { #ifdef CONFIG_OPENGL - if (!ensure_glx_context(ps)) - return false; - - if (!ps->psglx->glXSwapIntervalProc && !ps->psglx->glXSwapIntervalMESAProc) { - if (glx_has_extension(ps->dpy, ps->scr, "GLX_MESA_swap_control")) { - ps->psglx->glXSwapIntervalMESAProc = (f_SwapIntervalMESA) - glXGetProcAddress ((const GLubyte *) "glXSwapIntervalMESA"); - } else if (glx_has_extension(ps->dpy, ps->scr, "GLX_SGI_swap_control")) { - ps->psglx->glXSwapIntervalProc = (f_SwapIntervalSGI) - glXGetProcAddress ((const GLubyte *) "glXSwapIntervalSGI"); - } else { - log_error("Your driver doesn't support SGI_swap_control nor MESA_swap_control, giving up."); +static inline bool +vsync_opengl_swc_swap_interval(session_t *ps, unsigned int interval) { + if (glxext.has_GLX_MESA_swap_control) + return glXSwapIntervalMESA(interval) == 0; + else if (glxext.has_GLX_SGI_swap_control) + return glXSwapIntervalSGI(interval) == 0; + else if (glxext.has_GLX_EXT_swap_control) { + GLXDrawable d = glXGetCurrentDrawable(); + if (d == None) { + // We don't have a context?? return false; } + glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval); + return true; } - - if (ps->psglx->glXSwapIntervalMESAProc) - ps->psglx->glXSwapIntervalMESAProc(interval); - else if (ps->psglx->glXSwapIntervalProc) - ps->psglx->glXSwapIntervalProc(interval); - else - return false; -#endif - - return true; + return false; } +#endif static bool vsync_opengl_swc_init(session_t *ps) { @@ -216,8 +172,8 @@ static int vsync_opengl_wait(session_t *ps) { unsigned vblank_count = 0; - ps->psglx->glXGetVideoSyncSGI(&vblank_count); - ps->psglx->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); + glXGetVideoSyncSGI(&vblank_count); + glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); // I see some code calling glXSwapIntervalSGI(1) afterwards, is it required? return 0; @@ -232,8 +188,8 @@ static int vsync_opengl_oml_wait(session_t *ps) { int64_t ust = 0, msc = 0, sbc = 0; - ps->psglx->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); - ps->psglx->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, + glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); + glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); return 0;