Skip to content

Commit

Permalink
Merge pull request #1189 from yshui/libepoxy
Browse files Browse the repository at this point in the history
Use libepoxy + fix OpenBSD build
  • Loading branch information
yshui authored Feb 11, 2024
2 parents dff77aa + 642a43a commit 0e1628e
Show file tree
Hide file tree
Showing 16 changed files with 68 additions and 270 deletions.
1 change: 1 addition & 0 deletions .builds/freebsd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ packages:
- uthash
- libconfig
- libglvnd
- libepoxy
- dbus
- pcre
sources:
Expand Down
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ root = true
indent_style = tab
indent_size = 8
max_line_length = 90
[*.nix]
indent_style = space
indent_size = 2
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,21 @@ 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

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`
Expand Down
18 changes: 12 additions & 6 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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"
'';
};
});
}
103 changes: 16 additions & 87 deletions src/backend/gl/egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand Down Expand Up @@ -422,66 +395,22 @@ struct backend_operations egl_ops = {
.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};

void eglext_init(EGLDisplay dpy) {
if (eglext.initialized) {
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);
#ifdef EGL_MESA_query_driver
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
}
10 changes: 2 additions & 8 deletions src/backend/gl/egl.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <epoxy/egl.h>
#include <epoxy/gl.h>
#include <stdbool.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
Expand All @@ -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);
7 changes: 3 additions & 4 deletions src/backend/gl/gl_common.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <GL/gl.h>
#include <GL/glext.h>
#include <epoxy/gl.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -972,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;
Expand Down
23 changes: 1 addition & 22 deletions src/backend/gl/gl_common.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <GL/gl.h>
#include <GL/glext.h>
#include <epoxy/gl.h>
#include <stdbool.h>
#include <string.h>

Expand Down Expand Up @@ -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))

/**
* 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;

Expand Down
Loading

0 comments on commit 0e1628e

Please sign in to comment.