aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Zeni <simon@bl4ckb0ne.ca>2021-01-20 21:14:04 -0500
committerSimon Ser <contact@emersion.fr>2021-07-27 20:45:53 +0200
commit6f19295647fe9a1c0afec96eebd3947f1a52ec2b (patch)
tree0368a3fb4860216ae5c4c4cc8d33d0765f678258
parent7667ab73bdff671aad29452f33cc2e0e17c73d9e (diff)
render/egl: initialize wlr_egl with EGL_PLATFORM_DEVICE_EXT
Uses the EXT_device_query extension to get the EGL device matching the requested DRM file descriptor. If the extension is not supported or no device is found, the EGL device will be retrieved using GBM. Depends on the EGL_EXT_device_enumeration to get the list of EGL devices.
-rw-r--r--include/wlr/render/egl.h6
-rw-r--r--render/egl.c175
2 files changed, 146 insertions, 35 deletions
diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h
index 3a09ba97..903b70a3 100644
--- a/include/wlr/render/egl.h
+++ b/include/wlr/render/egl.h
@@ -44,6 +44,11 @@ struct wlr_egl {
// Device extensions
bool EXT_device_drm;
bool EXT_device_drm_render_node;
+
+ // Client extensions
+ bool EXT_device_query;
+ bool KHR_platform_gbm;
+ bool EXT_platform_device;
} exts;
struct {
@@ -56,6 +61,7 @@ struct wlr_egl {
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
+ PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
} procs;
struct wlr_drm_format_set dmabuf_texture_formats;
diff --git a/render/egl.c b/render/egl.c
index efb4e8d9..3b57b0d5 100644
--- a/render/egl.c
+++ b/render/egl.c
@@ -156,7 +156,7 @@ out:
free(formats);
}
-struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
+static struct wlr_egl *egl_create(void) {
struct wlr_egl *egl = calloc(1, sizeof(struct wlr_egl));
if (egl == NULL) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
@@ -172,11 +172,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
}
return NULL;
}
-
- if (!check_egl_ext(client_exts_str, "EGL_KHR_platform_gbm")) {
- wlr_log(WLR_ERROR, "EGL_KHR_platform_gbm not supported");
- return NULL;
- }
+ wlr_log(WLR_INFO, "Supported EGL client extensions: %s", client_exts_str);
if (!check_egl_ext(client_exts_str, "EGL_EXT_platform_base")) {
wlr_log(WLR_ERROR, "EGL_EXT_platform_base not supported");
@@ -185,6 +181,24 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
load_egl_proc(&egl->procs.eglGetPlatformDisplayEXT,
"eglGetPlatformDisplayEXT");
+ egl->exts.KHR_platform_gbm = check_egl_ext(client_exts_str,
+ "EGL_KHR_platform_gbm");
+
+ egl->exts.EXT_platform_device = check_egl_ext(client_exts_str,
+ "EGL_EXT_platform_device");
+
+ if (check_egl_ext(client_exts_str, "EGL_EXT_device_enumeration")) {
+ load_egl_proc(&egl->procs.eglQueryDevicesEXT, "eglQueryDevicesEXT");
+ }
+
+ if (check_egl_ext(client_exts_str, "EGL_EXT_device_query")) {
+ egl->exts.EXT_device_query = true;
+ load_egl_proc(&egl->procs.eglQueryDeviceStringEXT,
+ "eglQueryDeviceStringEXT");
+ load_egl_proc(&egl->procs.eglQueryDisplayAttribEXT,
+ "eglQueryDisplayAttribEXT");
+ }
+
if (check_egl_ext(client_exts_str, "EGL_KHR_debug")) {
load_egl_proc(&egl->procs.eglDebugMessageControlKHR,
"eglDebugMessageControlKHR");
@@ -201,32 +215,31 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
wlr_log(WLR_ERROR, "Failed to bind to the OpenGL ES API");
- goto error;
+ return NULL;
}
- egl->gbm_device = gbm_create_device(drm_fd);
- if (!egl->gbm_device) {
- wlr_log(WLR_ERROR, "Failed to create GBM device");
- goto error;
- }
+ return egl;
+}
- egl->display = egl->procs.eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR,
- egl->gbm_device, NULL);
+static bool egl_init(struct wlr_egl *egl, EGLenum platform,
+ void *remote_display) {
+ egl->display = egl->procs.eglGetPlatformDisplayEXT(platform,
+ remote_display, NULL);
if (egl->display == EGL_NO_DISPLAY) {
wlr_log(WLR_ERROR, "Failed to create EGL display");
- goto error;
+ return false;
}
EGLint major, minor;
if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) {
wlr_log(WLR_ERROR, "Failed to initialize EGL");
- goto error;
+ return false;
}
const char *display_exts_str = eglQueryString(egl->display, EGL_EXTENSIONS);
if (display_exts_str == NULL) {
wlr_log(WLR_ERROR, "Failed to query EGL display extensions");
- return NULL;
+ return false;
}
if (check_egl_ext(display_exts_str, "EGL_KHR_image_base")) {
@@ -247,17 +260,12 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
}
const char *device_exts_str = NULL, *driver_name = NULL;
- if (check_egl_ext(client_exts_str, "EGL_EXT_device_query")) {
- load_egl_proc(&egl->procs.eglQueryDisplayAttribEXT,
- "eglQueryDisplayAttribEXT");
- load_egl_proc(&egl->procs.eglQueryDeviceStringEXT,
- "eglQueryDeviceStringEXT");
-
+ if (egl->exts.EXT_device_query) {
EGLAttrib device_attrib;
if (!egl->procs.eglQueryDisplayAttribEXT(egl->display,
EGL_DEVICE_EXT, &device_attrib)) {
wlr_log(WLR_ERROR, "eglQueryDisplayAttribEXT(EGL_DEVICE_EXT) failed");
- goto error;
+ return false;
}
egl->device = (EGLDeviceEXT)device_attrib;
@@ -265,7 +273,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
egl->procs.eglQueryDeviceStringEXT(egl->device, EGL_EXTENSIONS);
if (device_exts_str == NULL) {
wlr_log(WLR_ERROR, "eglQueryDeviceStringEXT(EGL_EXTENSIONS) failed");
- goto error;
+ return false;
}
if (check_egl_ext(device_exts_str, "EGL_MESA_device_software")) {
@@ -276,7 +284,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
wlr_log(WLR_ERROR, "Software rendering detected, please use "
"the WLR_RENDERER_ALLOW_SOFTWARE environment variable "
"to proceed");
- goto error;
+ return false;
}
}
@@ -297,21 +305,19 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
!check_egl_ext(display_exts_str, "EGL_MESA_configless_context")) {
wlr_log(WLR_ERROR, "EGL_KHR_no_config_context or "
"EGL_MESA_configless_context not supported");
- goto error;
+ return false;
}
if (!check_egl_ext(display_exts_str, "EGL_KHR_surfaceless_context")) {
- wlr_log(WLR_ERROR,
- "EGL_KHR_surfaceless_context not supported");
- goto error;
+ wlr_log(WLR_ERROR, "EGL_KHR_surfaceless_context not supported");
+ return false;
}
- wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor);
- wlr_log(WLR_INFO, "Supported EGL client extensions: %s", client_exts_str);
wlr_log(WLR_INFO, "Supported EGL display extensions: %s", display_exts_str);
if (device_exts_str != NULL) {
wlr_log(WLR_INFO, "Supported EGL device extensions: %s", device_exts_str);
}
+ wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor);
wlr_log(WLR_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR));
if (driver_name != NULL) {
wlr_log(WLR_INFO, "EGL driver name: %s", driver_name);
@@ -345,7 +351,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
EGL_NO_CONTEXT, attribs);
if (egl->context == EGL_NO_CONTEXT) {
wlr_log(WLR_ERROR, "Failed to create EGL context");
- goto error;
+ return false;
}
if (request_high_priority) {
@@ -359,13 +365,112 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
}
}
- return egl;
+ return true;
+}
+
+static bool device_has_name(const drmDevice *device, const char *name);
+
+static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl,
+ int drm_fd) {
+ if (egl->procs.eglQueryDevicesEXT == NULL) {
+ wlr_log(WLR_DEBUG, "EGL_EXT_device_enumeration not supported");
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ EGLint nb_devices = 0;
+ if (!egl->procs.eglQueryDevicesEXT(0, NULL, &nb_devices)) {
+ wlr_log(WLR_ERROR, "Failed to query EGL devices");
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ EGLDeviceEXT *devices = calloc(nb_devices, sizeof(EGLDeviceEXT));
+ if (devices == NULL) {
+ wlr_log_errno(WLR_ERROR, "Failed to allocate EGL device list");
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ if (!egl->procs.eglQueryDevicesEXT(nb_devices, devices, &nb_devices)) {
+ wlr_log(WLR_ERROR, "Failed to query EGL devices");
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ drmDevice *device = NULL;
+ int ret = drmGetDevice(drm_fd, &device);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Failed to get DRM device: %s", strerror(-ret));
+ return EGL_NO_DEVICE_EXT;
+ }
+
+ EGLDeviceEXT egl_device = NULL;
+ for (int i = 0; i < nb_devices; i++) {
+ const char *egl_device_name = egl->procs.eglQueryDeviceStringEXT(
+ devices[i], EGL_DRM_DEVICE_FILE_EXT);
+ if (egl_device_name == NULL) {
+ continue;
+ }
+
+ if (device_has_name(device, egl_device_name)) {
+ wlr_log(WLR_DEBUG, "Using EGL device %s", egl_device_name);
+ egl_device = devices[i];
+ break;
+ }
+ }
+
+ free(devices);
+
+ return egl_device;
+}
+
+struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
+ struct wlr_egl *egl = egl_create();
+ if (egl == NULL) {
+ wlr_log(WLR_ERROR, "Failed to create EGL context");
+ return NULL;
+ }
+
+ if (egl->exts.EXT_platform_device) {
+ /*
+ * Search for the EGL device matching the DRM fd using the
+ * EXT_device_enumeration extension.
+ */
+ EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd);
+ if (egl_device != EGL_NO_DEVICE_EXT) {
+ if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
+ wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT");
+ return egl;
+ }
+ goto error;
+ }
+ /* Falls back on GBM in case the device was not found */
+ } else {
+ wlr_log(WLR_DEBUG, "EXT_platform_device not supported");
+ }
+
+ if (egl->exts.KHR_platform_gbm) {
+ egl->gbm_device = gbm_create_device(drm_fd);
+ if (!egl->gbm_device) {
+ wlr_log(WLR_ERROR, "Failed to create GBM device");
+ goto error;
+ }
+
+ if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device)) {
+ wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_GBM_KHR");
+ return egl;
+ }
+
+ gbm_device_destroy(egl->gbm_device);
+ } else {
+ wlr_log(WLR_DEBUG, "KHR_platform_gbm not supported");
+ }
error:
- eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ wlr_log(WLR_ERROR, "Failed to initialize EGL context");
if (egl->display) {
+ eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
eglTerminate(egl->display);
}
+ free(egl);
eglReleaseThread();
return NULL;
}