106
src/egl_override.c
Normal file
106
src/egl_override.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Some drivers expose EGL_EXT_create_context_robustness, which wlroots
|
||||||
|
// consumes to request EGL_LOSE_CONTEXT_ON_RESET_EXT. Monado rejects sharing
|
||||||
|
// contexts with mismatched reset notification strategies, so hide that
|
||||||
|
// extension from wlroots by overriding eglQueryString.
|
||||||
|
|
||||||
|
typedef const char *(*eglQueryStringFn)(EGLDisplay display, EGLint name);
|
||||||
|
|
||||||
|
static const char *strip_extension(const char *exts, const char *target)
|
||||||
|
{
|
||||||
|
if (!exts || !target || *target == '\0') {
|
||||||
|
return exts;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t target_len = strlen(target);
|
||||||
|
const char *found = strstr(exts, target);
|
||||||
|
if (!found) {
|
||||||
|
return exts;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *copy = strdup(exts);
|
||||||
|
if (!copy) {
|
||||||
|
return exts;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *start = strstr(copy, target);
|
||||||
|
while (start) {
|
||||||
|
char *end = start + target_len;
|
||||||
|
|
||||||
|
// Trim leading spaces before the target substring.
|
||||||
|
while (start > copy && start[-1] == ' ') {
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip trailing spaces after the target substring.
|
||||||
|
while (*end == ' ') {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(start, end, strlen(end) + 1);
|
||||||
|
start = strstr(start, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapse duplicate spaces introduced by removals.
|
||||||
|
char *dst = copy;
|
||||||
|
bool prev_space = false;
|
||||||
|
for (char *src = copy; *src; ++src) {
|
||||||
|
if (*src == ' ') {
|
||||||
|
if (prev_space) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
prev_space = true;
|
||||||
|
} else {
|
||||||
|
prev_space = false;
|
||||||
|
}
|
||||||
|
*dst++ = *src;
|
||||||
|
}
|
||||||
|
// Trim any trailing space left at the end.
|
||||||
|
if (dst > copy && dst[-1] == ' ') {
|
||||||
|
--dst;
|
||||||
|
}
|
||||||
|
*dst = '\0';
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *eglQueryString(EGLDisplay display, EGLint name)
|
||||||
|
{
|
||||||
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static eglQueryStringFn real_eglQueryString = NULL;
|
||||||
|
static const char *cached_extensions = NULL;
|
||||||
|
|
||||||
|
if (!real_eglQueryString) {
|
||||||
|
real_eglQueryString = (eglQueryStringFn)dlsym(RTLD_NEXT, "eglQueryString");
|
||||||
|
if (!real_eglQueryString) {
|
||||||
|
fprintf(stderr, "lunarwm: failed to resolve real eglQueryString\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *result = real_eglQueryString(display, name);
|
||||||
|
if (name != EGL_EXTENSIONS || result == NULL) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
if (cached_extensions == NULL) {
|
||||||
|
cached_extensions = strip_extension(result, "EGL_EXT_create_context_robustness");
|
||||||
|
if (cached_extensions == result) {
|
||||||
|
cached_extensions = strdup(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char *filtered = cached_extensions;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user