mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-31 22:25:21 -04:00
render: add wlr_egl_create_from_drm_fd function
This function relies on the extension EGL_WL_bind_wayland_display being present. If not, the creation of `wlr_egl` will fallback on using GBM
This commit is contained in:
parent
84dea55b20
commit
074e36deb6
4 changed files with 173 additions and 49 deletions
15
include/render/egl.h
Normal file
15
include/render/egl.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef RENDER_EGL_H
|
||||
#define RENDER_EGL_H
|
||||
|
||||
#include <wlr/render/egl.h>
|
||||
|
||||
/**
|
||||
* Creates and EGL context from a given drm fd. This function uses the
|
||||
* following extensions:
|
||||
* - EXT_device_enumeration to get the list of available EGLDeviceEXT
|
||||
* - EXT_device_drm to get the name of the EGLDeviceEXT
|
||||
* - EXT_platform_device to create an EGLDisplay from an EGLDeviceEXT
|
||||
*/
|
||||
struct wlr_egl *wlr_egl_create_from_drm_fd(int drm_fd);
|
||||
|
||||
#endif
|
||||
|
|
@ -51,6 +51,9 @@ struct wlr_egl {
|
|||
|
||||
// Device extensions
|
||||
bool device_drm_ext;
|
||||
|
||||
// Client extensions
|
||||
bool device_query_ext;
|
||||
} exts;
|
||||
|
||||
struct {
|
||||
|
|
@ -65,6 +68,7 @@ struct wlr_egl {
|
|||
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
|
||||
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
|
||||
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
|
||||
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
|
||||
} procs;
|
||||
|
||||
struct wl_display *wl_display;
|
||||
|
|
|
|||
191
render/egl.c
191
render/egl.c
|
|
@ -11,6 +11,8 @@
|
|||
#include <wlr/util/region.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include "render/egl.h"
|
||||
|
||||
static enum wlr_log_importance egl_log_importance_to_wlr(EGLint type) {
|
||||
switch (type) {
|
||||
case EGL_DEBUG_MSG_CRITICAL_KHR: return WLR_ERROR;
|
||||
|
|
@ -155,7 +157,7 @@ out:
|
|||
free(formats);
|
||||
}
|
||||
|
||||
struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
||||
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");
|
||||
|
|
@ -171,12 +173,11 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
wlr_log(WLR_INFO, "Supported EGL client extensions: %s", client_exts_str);
|
||||
|
||||
if (platform == EGL_PLATFORM_GBM_KHR) {
|
||||
if (!check_egl_ext(client_exts_str, "EGL_KHR_platform_gbm")) {
|
||||
wlr_log(WLR_ERROR, "EGL_KHR_platform_gbm not supported");
|
||||
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;
|
||||
}
|
||||
|
||||
if (!check_egl_ext(client_exts_str, "EGL_EXT_platform_base")) {
|
||||
|
|
@ -186,6 +187,18 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
load_egl_proc(&egl->procs.eglGetPlatformDisplayEXT,
|
||||
"eglGetPlatformDisplayEXT");
|
||||
|
||||
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.device_query_ext = 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");
|
||||
|
|
@ -202,26 +215,31 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
|
||||
if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
|
||||
wlr_log(WLR_ERROR, "Failed to bind to the OpenGL ES API");
|
||||
goto error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return egl;
|
||||
}
|
||||
|
||||
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")) {
|
||||
|
|
@ -249,20 +267,19 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
"eglUnbindWaylandDisplayWL");
|
||||
load_egl_proc(&egl->procs.eglQueryWaylandBufferWL,
|
||||
"eglQueryWaylandBufferWL");
|
||||
} else if (platform == EGL_PLATFORM_DEVICE_EXT) {
|
||||
wlr_log(WLR_DEBUG, "EGL_WL_bind_wayland_display not supported");
|
||||
wlr_log(WLR_DEBUG, "Falling back to GBM platform");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *device_exts_str = 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.device_query_ext) {
|
||||
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;
|
||||
|
||||
|
|
@ -270,7 +287,7 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
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")) {
|
||||
|
|
@ -296,21 +313,19 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
!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));
|
||||
|
||||
init_dmabuf_formats(egl);
|
||||
|
|
@ -341,7 +356,7 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
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) {
|
||||
|
|
@ -355,13 +370,123 @@ struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
|||
}
|
||||
}
|
||||
|
||||
return egl;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display) {
|
||||
struct wlr_egl *egl = egl_create();
|
||||
if (egl == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create EGL context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!egl_init(egl, platform, remote_display)) {
|
||||
wlr_log(WLR_ERROR, "Failed to initialize EGL context");
|
||||
eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
if (egl->display) {
|
||||
eglTerminate(egl->display);
|
||||
}
|
||||
free(egl);
|
||||
eglReleaseThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return egl;
|
||||
}
|
||||
|
||||
static bool device_has_name(const drmDevice *device, const char *name) {
|
||||
for (size_t i = 0; i < DRM_NODE_MAX; i++) {
|
||||
if (!(device->available_nodes & (1 << i))) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(device->nodes[i], name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_egl *wlr_egl_create_from_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->procs.eglQueryDevicesEXT == NULL) {
|
||||
wlr_log(WLR_ERROR, "EGL_EXT_device_enumeration not supported");
|
||||
goto error;
|
||||
}
|
||||
|
||||
EGLint nb_devices = 0;
|
||||
if (!egl->procs.eglQueryDevicesEXT(0, NULL, &nb_devices)) {
|
||||
wlr_log(WLR_ERROR, "Failed to query EGL devices");
|
||||
goto error;
|
||||
}
|
||||
|
||||
EGLDeviceEXT *devices = calloc(nb_devices, sizeof(EGLDeviceEXT));
|
||||
if (devices == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to allocate device list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!egl->procs.eglQueryDevicesEXT(nb_devices, devices, &nb_devices)) {
|
||||
wlr_log(WLR_ERROR, "Failed to query EGL devices");
|
||||
goto error;
|
||||
}
|
||||
|
||||
drmDevice *device = NULL;
|
||||
int ret = drmGetDevice(drm_fd, &device);
|
||||
if (ret < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to get DRM device: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (egl_device == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to find EGLDeviceEXT");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
|
||||
return egl;
|
||||
}
|
||||
|
||||
// Fallback to GBM
|
||||
struct gbm_device *gbm_device = gbm_create_device(drm_fd);
|
||||
if (!gbm_device) {
|
||||
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (egl_init(egl, EGL_PLATFORM_GBM_KHR, gbm_device)) {
|
||||
return egl;
|
||||
}
|
||||
|
||||
wlr_log(WLR_ERROR, "Failed to initialize EGL context");
|
||||
gbm_device_destroy(gbm_device);
|
||||
error:
|
||||
eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (egl->display) {
|
||||
eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
eglTerminate(egl->display);
|
||||
}
|
||||
free(egl);
|
||||
eglReleaseThread();
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -691,18 +816,6 @@ const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats(
|
|||
return &egl->dmabuf_render_formats;
|
||||
}
|
||||
|
||||
static bool device_has_name(const drmDevice *device, const char *name) {
|
||||
for (size_t i = 0; i < DRM_NODE_MAX; i++) {
|
||||
if (!(device->available_nodes & (1 << i))) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(device->nodes[i], name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *get_render_name(const char *name) {
|
||||
uint32_t flags = 0;
|
||||
int devices_len = drmGetDevices2(flags, NULL, 0);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "util/signal.h"
|
||||
#include "render/egl.h"
|
||||
#include "render/pixel_format.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
|
||||
|
|
@ -221,21 +222,12 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
|
|||
}
|
||||
|
||||
struct wlr_renderer *wlr_renderer_autocreate_with_drm_fd(int drm_fd) {
|
||||
struct gbm_device *gbm_device = gbm_create_device(drm_fd);
|
||||
if (!gbm_device) {
|
||||
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_egl *egl = wlr_egl_create(EGL_PLATFORM_GBM_KHR, gbm_device);
|
||||
struct wlr_egl *egl = wlr_egl_create_from_drm_fd(drm_fd);
|
||||
if (egl == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not initialize EGL");
|
||||
gbm_device_destroy(gbm_device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
egl->gbm_device = gbm_device;
|
||||
|
||||
struct wlr_renderer *renderer = wlr_gles2_renderer_create(egl);
|
||||
if (!renderer) {
|
||||
wlr_log(WLR_ERROR, "Failed to create GLES2 renderer");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue