mirror of https://github.com/yshui/picom.git
Merge pull request #1189 from yshui/libepoxy
Use libepoxy + fix OpenBSD build
This commit is contained in:
commit
0e1628e031
|
@ -12,6 +12,7 @@ packages:
|
||||||
- uthash
|
- uthash
|
||||||
- libconfig
|
- libconfig
|
||||||
- libglvnd
|
- libglvnd
|
||||||
|
- libepoxy
|
||||||
- dbus
|
- dbus
|
||||||
- pcre
|
- pcre
|
||||||
sources:
|
sources:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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`
|
||||||
|
|
18
flake.nix
18
flake.nix
|
@ -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"
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
31
src/log.c
31
src/log.c
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue