Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use libepoxy #1189

Merged
merged 4 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
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);

Check warning on line 71 in src/backend/gl/egl.c

View check run for this annotation

Codecov / codecov/patch

src/backend/gl/egl.c#L71

Added line #L71 was not covered by tests
p->image = EGL_NO_IMAGE;
}

Expand Down Expand Up @@ -134,18 +128,6 @@
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 @@
}

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 @@
// clang-format on

gd->target_win =
eglCreatePlatformWindowSurfaceProc(gd->display, config, &target, NULL);
eglCreatePlatformWindowSurfaceEXT(gd->display, config, &target, NULL);

Check warning on line 197 in src/backend/gl/egl.c

View check run for this annotation

Codecov / codecov/patch

src/backend/gl/egl.c#L197

Added line #L197 was not covered by tests
if (gd->target_win == EGL_NO_SURFACE) {
log_error("Failed to create EGL surface.");
goto end;
Expand Down Expand Up @@ -243,14 +225,6 @@
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 @@

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);

Check warning on line 280 in src/backend/gl/egl.c

View check run for this annotation

Codecov / codecov/patch

src/backend/gl/egl.c#L279-L280

Added lines #L279 - L280 were not covered by tests
eglpixmap->owned = owned;

if (eglpixmap->image == EGL_NO_IMAGE) {
Expand All @@ -324,14 +297,14 @@
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);

Check warning on line 300 in src/backend/gl/egl.c

View check run for this annotation

Codecov / codecov/patch

src/backend/gl/egl.c#L300

Added line #L300 was not covered by tests
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);

Check warning on line 307 in src/backend/gl/egl.c

View check run for this annotation

Codecov / codecov/patch

src/backend/gl/egl.c#L307

Added line #L307 was not covered by tests
}
free(eglpixmap);

Expand Down Expand Up @@ -422,66 +395,22 @@
.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
Loading