mirror of
https://github.com/yshui/picom.git
synced 2024-11-11 13:51:02 -05:00
backend: gl: use libepoxy
There is actually no specification what symbols are exported from a libGL implementation. The (extremely outdated) OpenGL ABI specification says only GL 1.2 functions are guaranteed. Don't know how relevant that is now, but different libGL implementations do export different set of symbols. On Linux we are most likely to be linked with libglvnd, which has everything we need. But on other platforms this is not necessarily the case, for example on OpenBSD we are missing glGetQueryObjectui64v. Use libepoxy so we can outsource this problem and never worry about it ever again. Plus it also saves us from calling GetProcAddress ourselves. Changes other than trivial build fixes I have to make: 1. Can't use eglCreatePlatformWindowSurface/eglGetPlatformDisplay. libepoxy checks for EGL 1.5 when resolving these functions. But without a current context, libepoxy assumes we only have EGL 1.4. This creates a chicken and egg problem - we need a display to call eglGetPlatformDisplay. We have to use the *EXT version instead. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
fcd51e7373
commit
eb723eee29
10 changed files with 32 additions and 163 deletions
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -422,7 +395,6 @@ struct backend_operations egl_ops = {
|
|||
.max_buffer_age = 5, // Why?
|
||||
};
|
||||
|
||||
PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName;
|
||||
/**
|
||||
* Check if a EGL extension exists.
|
||||
*/
|
||||
|
@ -472,16 +444,4 @@ void eglext_init(EGLDisplay dpy) {
|
|||
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
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -580,16 +580,6 @@ static inline bool glx_has_extension(Display *dpy, int screen, const char *ext)
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -614,36 +604,4 @@ void glxext_init(Display *dpy, int screen) {
|
|||
check_ext(GLX_MESA_query_renderer);
|
||||
#endif
|
||||
#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
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#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 <epoxy/glx.h>
|
||||
#include <stdbool.h>
|
||||
#include <xcb/render.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
|
@ -59,19 +51,4 @@ struct glxext_info {
|
|||
|
||||
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);
|
||||
|
|
29
src/log.c
29
src/log.c
|
@ -9,7 +9,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include <GL/gl.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include "backend/gl/gl_common.h"
|
||||
#include "backend/gl/glx.h"
|
||||
#endif
|
||||
|
@ -338,21 +338,14 @@ struct log_target *stderr_logger_new(void) {
|
|||
}
|
||||
|
||||
#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
|
||||
gl_string_marker_logger_write(struct log_target *tgt, const char *str, size_t len) {
|
||||
auto g = (struct gl_string_marker_logger *)tgt;
|
||||
static void gl_string_marker_logger_write(struct log_target *tgt attr_unused,
|
||||
const char *str, size_t len) {
|
||||
// strip newlines at the end of the string
|
||||
while (len > 0 && str[len - 1] == '\n') {
|
||||
len--;
|
||||
}
|
||||
g->gl_string_marker((GLsizei)len, str);
|
||||
glStringMarkerGREMEDY((GLsizei)len, str);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
/// 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) {
|
||||
if (!gl_has_extension("GL_GREMEDY_string_marker")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *fnptr = glXGetProcAddress((GLubyte *)"glStringMarkerGREMEDY");
|
||||
if (!fnptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto ret = cmalloc(struct gl_string_marker_logger);
|
||||
ret->tgt.ops = &gl_string_marker_logger_ops;
|
||||
ret->gl_string_marker = fnptr;
|
||||
return &ret->tgt;
|
||||
auto ret = cmalloc(struct log_target);
|
||||
ret->ops = &gl_string_marker_logger_ops;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -58,8 +58,8 @@ if get_option('vsync_drm')
|
|||
endif
|
||||
|
||||
if get_option('opengl')
|
||||
cflags += ['-DCONFIG_OPENGL', '-DGL_GLEXT_PROTOTYPES']
|
||||
deps += [dependency('gl', required: true), dependency('egl', required: true)]
|
||||
cflags += ['-DCONFIG_OPENGL']
|
||||
deps += [dependency('epoxy', required: true)]
|
||||
srcs += [ 'opengl.c' ]
|
||||
endif
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
#include "render.h"
|
||||
#include "win.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
#include <ctype.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/glx.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
#ifdef CONFIG_OPENGL
|
||||
// Enable sgi_video_sync_vblank_scheduler
|
||||
#include <GL/glx.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <epoxy/glx.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#endif
|
||||
|
@ -96,8 +96,6 @@ struct sgi_video_sync_thread_args {
|
|||
pthread_cond_t start_cnd;
|
||||
};
|
||||
|
||||
static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI;
|
||||
|
||||
static bool check_sgi_video_sync_extension(Display *dpy, int screen) {
|
||||
const char *glx_ext = glXQueryExtensionsString(dpy, screen);
|
||||
const char *needle = "GLX_SGI_video_sync";
|
||||
|
@ -112,11 +110,6 @@ static bool check_sgi_video_sync_extension(Display *dpy, int screen) {
|
|||
return false;
|
||||
}
|
||||
|
||||
glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC)(void *)glXGetProcAddress(
|
||||
(const GLubyte *)"glXWaitVideoSyncSGI");
|
||||
if (!glXWaitVideoSyncSGI) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue