Merge pull request #1189 from yshui/libepoxy

Use libepoxy + fix OpenBSD build
This commit is contained in:
Yuxuan Shui 2024-02-11 17:27:32 +01:00 committed by GitHub
commit 0e1628e031
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 68 additions and 270 deletions

View File

@ -12,6 +12,7 @@ packages:
- uthash - uthash
- libconfig - libconfig
- libglvnd - libglvnd
- libepoxy
- dbus - dbus
- pcre - pcre
sources: sources:

View File

@ -3,3 +3,6 @@ root = true
indent_style = tab indent_style = tab
indent_size = 8 indent_size = 8
max_line_length = 90 max_line_length = 90
[*.nix]
indent_style = space
indent_size = 2

View File

@ -4,9 +4,14 @@
* Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170) * 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 ## Bug fixes
* Workaround a NVIDIA problem that causes high CPU usage after suspend/resume (#1172, #1168) * 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) # v11.1 (2024-Jan-28)

View File

@ -41,7 +41,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
* pixman * pixman
* libdbus (optional, disable with the `-Ddbus=false` meson configure flag) * libdbus (optional, disable with the `-Ddbus=false` meson configure flag)
* libconfig (optional, disable with the `-Dconfig_file=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) * libpcre2 (optional, disable with the `-Dregex=false` meson configure flag)
* libev * libev
* uthash * 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 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 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` To build the documents, you need `asciidoc`

View File

@ -24,16 +24,22 @@
overlays = [ overlay ]; overlays = [ overlay ];
in rec { in rec {
inherit overlay overlays; inherit overlay overlays;
defaultPackage = pkgs.picom.overrideAttrs { defaultPackage = pkgs.picom.overrideAttrs (o: {
version = "11"; version = "11";
src = ./.; src = ./.;
}; buildInputs = o.buildInputs ++ [ pkgs.libepoxy ];
});
devShell = defaultPackage.overrideAttrs { devShell = defaultPackage.overrideAttrs {
buildInputs = defaultPackage.buildInputs ++ [ buildInputs = defaultPackage.buildInputs ++ (with pkgs; [
pkgs.clang-tools_17 clang-tools_17
pkgs.llvmPackages_17.clang-unwrapped.python llvmPackages_17.clang-unwrapped.python
]; ]);
hardeningDisable = [ "fortify" ]; 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"
'';
}; };
}); });
} }

View File

@ -36,12 +36,6 @@ struct egl_data {
EGLContext ctx; 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) { const char *eglGetErrorString(EGLint error) {
#define CASE_STR(value) \ #define CASE_STR(value) \
case value: return #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; struct egl_pixmap *p = tex->user_data;
// Release binding // Release binding
if (p->image != EGL_NO_IMAGE) { if (p->image != EGL_NO_IMAGE) {
eglDestroyImageProc(gd->display, p->image); eglDestroyImage(gd->display, p->image);
p->image = EGL_NO_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; bool success = false;
struct egl_data *gd = NULL; 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 // Check if we have the X11 platform
const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (strstr(exts, "EGL_EXT_platform_x11") == NULL) { 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 = ccalloc(1, struct egl_data);
gd->display = eglGetPlatformDisplayProc(EGL_PLATFORM_X11_EXT, ps->c.dpy, gd->display = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, ps->c.dpy,
(EGLAttrib[]){ (EGLint[]){
EGL_PLATFORM_X11_SCREEN_EXT, EGL_PLATFORM_X11_SCREEN_EXT,
ps->c.screen, ps->c.screen,
EGL_NONE, EGL_NONE,
}); });
if (gd->display == EGL_NO_DISPLAY) { if (gd->display == EGL_NO_DISPLAY) {
log_error("Failed to get EGL display."); log_error("Failed to get EGL display.");
goto end; goto end;
@ -212,7 +194,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
// clang-format on // clang-format on
gd->target_win = gd->target_win =
eglCreatePlatformWindowSurfaceProc(gd->display, config, &target, NULL); eglCreatePlatformWindowSurfaceEXT(gd->display, config, &target, NULL);
if (gd->target_win == EGL_NO_SURFACE) { if (gd->target_win == EGL_NO_SURFACE) {
log_error("Failed to create EGL surface."); log_error("Failed to create EGL surface.");
goto end; goto end;
@ -243,14 +225,6 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
goto end; 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.decouple_texture_user_data = egl_decouple_user_data;
gd->gl.release_user_data = egl_release_image; 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 = cmalloc(struct egl_pixmap);
eglpixmap->pixmap = pixmap; eglpixmap->pixmap = pixmap;
eglpixmap->image = eglpixmap->image = eglCreateImage(gd->display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
eglCreateImageProc(gd->display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)(uintptr_t)pixmap, NULL);
(EGLClientBuffer)(uintptr_t)pixmap, NULL);
eglpixmap->owned = owned; eglpixmap->owned = owned;
if (eglpixmap->image == EGL_NO_IMAGE) { 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->dim = 0;
wd->inner->refcount = 1; wd->inner->refcount = 1;
glBindTexture(GL_TEXTURE_2D, inner->texture); 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); glBindTexture(GL_TEXTURE_2D, 0);
gl_check_err(); gl_check_err();
return wd; return wd;
err: err:
if (eglpixmap && eglpixmap->image) { if (eglpixmap && eglpixmap->image) {
eglDestroyImageProc(gd->display, eglpixmap->image); eglDestroyImage(gd->display, eglpixmap->image);
} }
free(eglpixmap); free(eglpixmap);
@ -422,41 +395,6 @@ struct backend_operations egl_ops = {
.max_buffer_age = 5, // Why? .max_buffer_age = 5, // Why?
}; };
PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName;
/**
* 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}; struct eglext_info eglext = {0};
void eglext_init(EGLDisplay dpy) { void eglext_init(EGLDisplay dpy) {
@ -464,7 +402,10 @@ void eglext_init(EGLDisplay dpy) {
return; return;
} }
eglext.initialized = true; 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_buffer_age);
check_ext(EGL_EXT_create_context_robustness); check_ext(EGL_EXT_create_context_robustness);
check_ext(EGL_KHR_image_pixmap); check_ext(EGL_KHR_image_pixmap);
@ -472,16 +413,4 @@ void eglext_init(EGLDisplay dpy) {
check_ext(EGL_MESA_query_driver); check_ext(EGL_MESA_query_driver);
#endif #endif
#undef check_ext #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
} }

View File

@ -1,10 +1,8 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com> // Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once #pragma once
#include <EGL/egl.h> #include <epoxy/egl.h>
#include <EGL/eglext.h> #include <epoxy/gl.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <stdbool.h> #include <stdbool.h>
#include <xcb/render.h> #include <xcb/render.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
@ -24,8 +22,4 @@ struct eglext_info {
extern struct eglext_info eglext; extern struct eglext_info eglext;
#ifdef EGL_MESA_query_driver
extern PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName;
#endif
void eglext_init(EGLDisplay); void eglext_init(EGLDisplay);

View File

@ -1,7 +1,6 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com> // Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <GL/gl.h> #include <epoxy/gl.h>
#include <GL/glext.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -972,8 +971,8 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
} else { } else {
gd->is_nvidia = false; gd->is_nvidia = false;
} }
gd->has_robustness = gl_has_extension("GL_ARB_robustness"); gd->has_robustness = epoxy_has_gl_extension("GL_ARB_robustness");
gd->has_egl_image_storage = gl_has_extension("GL_EXT_EGL_image_storage"); gd->has_egl_image_storage = epoxy_has_gl_extension("GL_EXT_EGL_image_storage");
gl_check_err(); gl_check_err();
return true; return true;

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com> // Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once #pragma once
#include <GL/gl.h> #include <epoxy/gl.h>
#include <GL/glext.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
@ -264,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)) #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_coord_loc = 0;
static const GLuint vert_in_texcoord_loc = 1; static const GLuint vert_in_texcoord_loc = 1;

View File

@ -545,62 +545,17 @@ struct backend_operations glx_ops = {
.max_buffer_age = 5, // Why? .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}; 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;
#endif
void glxext_init(Display *dpy, int screen) { void glxext_init(Display *dpy, int screen) {
if (glxext.initialized) { if (glxext.initialized) {
return; return;
} }
glxext.initialized = true; 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_video_sync);
check_ext(GLX_SGI_swap_control); check_ext(GLX_SGI_swap_control);
check_ext(GLX_OML_sync_control); check_ext(GLX_OML_sync_control);
@ -614,36 +569,4 @@ void glxext_init(Display *dpy, int screen) {
check_ext(GLX_MESA_query_renderer); check_ext(GLX_MESA_query_renderer);
#endif #endif
#undef check_ext #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
} }

View File

@ -1,17 +1,9 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com> // Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once #pragma once
#include <stdbool.h>
// 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 <GL/glx.h>
#undef glXSwapIntervalMESA
#undef glXBindTexImageEXT
#undef glXReleaseTexImageEXT
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <epoxy/glx.h>
#include <stdbool.h>
#include <xcb/render.h> #include <xcb/render.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
@ -59,19 +51,4 @@ struct glxext_info {
extern struct glxext_info glxext; 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); void glxext_init(Display *, int screen);

View File

@ -9,7 +9,7 @@
#include <unistd.h> #include <unistd.h>
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
#include <GL/gl.h> #include <epoxy/gl.h>
#include "backend/gl/gl_common.h" #include "backend/gl/gl_common.h"
#include "backend/gl/glx.h" #include "backend/gl/glx.h"
#endif #endif
@ -338,21 +338,14 @@ struct log_target *stderr_logger_new(void) {
} }
#ifdef CONFIG_OPENGL #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 static void gl_string_marker_logger_write(struct log_target *tgt attr_unused,
gl_string_marker_logger_write(struct log_target *tgt, const char *str, size_t len) { const char *str, size_t len) {
auto g = (struct gl_string_marker_logger *)tgt;
// strip newlines at the end of the string // strip newlines at the end of the string
while (len > 0 && str[len - 1] == '\n') { while (len > 0 && str[len - 1] == '\n') {
len--; len--;
} }
g->gl_string_marker((GLsizei)len, str); glStringMarkerGREMEDY((GLsizei)len, str);
} }
static const struct log_ops gl_string_marker_logger_ops = { 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, .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) { 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; return NULL;
} }
void *fnptr = glXGetProcAddress((GLubyte *)"glStringMarkerGREMEDY"); auto ret = cmalloc(struct log_target);
if (!fnptr) { ret->ops = &gl_string_marker_logger_ops;
return NULL; return ret;
}
auto ret = cmalloc(struct gl_string_marker_logger);
ret->tgt.ops = &gl_string_marker_logger_ops;
ret->gl_string_marker = fnptr;
return &ret->tgt;
} }
#else #else

View File

@ -58,8 +58,8 @@ if get_option('vsync_drm')
endif endif
if get_option('opengl') if get_option('opengl')
cflags += ['-DCONFIG_OPENGL', '-DGL_GLEXT_PROTOTYPES'] cflags += ['-DCONFIG_OPENGL']
deps += [dependency('gl', required: true), dependency('egl', required: true)] deps += [dependency('epoxy', required: true)]
srcs += [ 'opengl.c' ] srcs += [ 'opengl.c' ]
endif endif

View File

@ -181,7 +181,7 @@ bool glx_init(session_t *ps, bool need_render) {
// must precede FBConfig fetching // must precede FBConfig fetching
if (need_render) { if (need_render) {
psglx->has_texture_non_power_of_two = 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 // Render preparations

View File

@ -18,9 +18,9 @@
#include "render.h" #include "render.h"
#include "win.h" #include "win.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include <ctype.h> #include <ctype.h>
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <locale.h> #include <locale.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@ -11,11 +11,11 @@
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
// Enable sgi_video_sync_vblank_scheduler // Enable sgi_video_sync_vblank_scheduler
#include <GL/glx.h>
#include <X11/X.h> #include <X11/X.h>
#include <X11/Xlib-xcb.h> #include <X11/Xlib-xcb.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <epoxy/glx.h>
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -96,8 +96,6 @@ struct sgi_video_sync_thread_args {
pthread_cond_t start_cnd; pthread_cond_t start_cnd;
}; };
static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI;
static bool check_sgi_video_sync_extension(Display *dpy, int screen) { static bool check_sgi_video_sync_extension(Display *dpy, int screen) {
const char *glx_ext = glXQueryExtensionsString(dpy, screen); const char *glx_ext = glXQueryExtensionsString(dpy, screen);
const char *needle = "GLX_SGI_video_sync"; const char *needle = "GLX_SGI_video_sync";
@ -112,11 +110,6 @@ static bool check_sgi_video_sync_extension(Display *dpy, int screen) {
return false; return false;
} }
glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC)(void *)glXGetProcAddress(
(const GLubyte *)"glXWaitVideoSyncSGI");
if (!glXWaitVideoSyncSGI) {
return false;
}
return true; return true;
} }