diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index ee8b04d6..938dc1ab 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(wlr-backend drm/backend.c drm/drm.c drm/udev.c + egl.c ) target_link_libraries(wlr-backend diff --git a/backend/egl.c b/backend/egl.c new file mode 100644 index 00000000..b6c49846 --- /dev/null +++ b/backend/egl.c @@ -0,0 +1,169 @@ +#include +#include +#include // GBM_FORMAT_XRGB8888 + +#include "backend/egl.h" +#include "common/log.h" + +static const char *egl_error(void) { + switch (eglGetError()) { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "Not initialized"; + case EGL_BAD_ACCESS: + return "Bad access"; + case EGL_BAD_ALLOC: + return "Bad alloc"; + case EGL_BAD_ATTRIBUTE: + return "Bad attribute"; + case EGL_BAD_CONTEXT: + return "Bad Context"; + case EGL_BAD_CONFIG: + return "Bad Config"; + case EGL_BAD_CURRENT_SURFACE: + return "Bad current surface"; + case EGL_BAD_DISPLAY: + return "Bad display"; + case EGL_BAD_SURFACE: + return "Bad surface"; + case EGL_BAD_MATCH: + return "Bad match"; + case EGL_BAD_PARAMETER: + return "Bad parameter"; + case EGL_BAD_NATIVE_PIXMAP: + return "Bad native pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "Bad native window"; + case EGL_CONTEXT_LOST: + return "Context lost"; + default: + return "Unknown"; + } +} + +// EGL extensions +PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display; +PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window_surface; + +static bool egl_exts() { + get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC) + eglGetProcAddress("eglGetPlatformDisplayEXT"); + + if (!get_platform_display) { + wlr_log(L_ERROR, "Failed to load EGL extension 'eglGetPlatformDisplayEXT'"); + return false; + } + + create_platform_window_surface = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) + eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); + + if (!get_platform_display) { + wlr_log(L_ERROR, + "Failed to load EGL extension 'eglCreatePlatformWindowSurfaceEXT'"); + return false; + } + + return true; +} + +static bool egl_get_config(EGLDisplay disp, EGLConfig *out) { + EGLint count = 0, matched = 0, ret; + + ret = eglGetConfigs(disp, NULL, 0, &count); + if (ret == EGL_FALSE || count == 0) { + return false; + } + + EGLConfig configs[count]; + + ret = eglChooseConfig(disp, NULL, configs, count, &matched); + if (ret == EGL_FALSE) { + return false; + } + + for (int i = 0; i < matched; ++i) { + EGLint gbm_format; + + if (!eglGetConfigAttrib(disp, + configs[i], + EGL_NATIVE_VISUAL_ID, + &gbm_format)) { + continue; + } + + // XXX: Is GBM_FORMAT_XRGB8888 what we want? + // I don't know if this works for wl_displays. + if (gbm_format == GBM_FORMAT_XRGB8888) { + *out = configs[i]; + return true; + } + } + + return false; +} + + +bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display) { + if (!egl_exts()) { + return false; + } + + if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) { + wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API: %s", egl_error()); + goto error; + } + + egl->display = get_platform_display(platform, display, NULL); + if (egl->display == EGL_NO_DISPLAY) { + wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error()); + goto error; + } + + if (eglInitialize(egl->display, NULL, NULL) == EGL_FALSE) { + wlr_log(L_ERROR, "Failed to initialize EGL: %s", egl_error()); + goto error; + } + + if (!egl_get_config(egl->display, &egl->config)) { + wlr_log(L_ERROR, "Failed to get EGL config"); + goto error; + } + + static const EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; + + egl->context = eglCreateContext(egl->display, egl->config, + EGL_NO_CONTEXT, attribs); + + if (egl->context == EGL_NO_CONTEXT) { + wlr_log(L_ERROR, "Failed to create EGL context: %s", egl_error()); + goto error; + } + + return true; + +error: + eglTerminate(egl->display); + eglReleaseThread(); + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + return false; +} + +void wlr_egl_free(struct wlr_egl *egl) { + eglDestroyContext(egl->display, egl->context); + eglTerminate(egl->display); + eglReleaseThread(); + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { + EGLSurface surf = create_platform_window_surface(egl->display, egl->config, + window, NULL); + if (surf == EGL_NO_SURFACE) { + wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); + return EGL_NO_SURFACE; + } + + return surf; +} diff --git a/include/backend/egl.h b/include/backend/egl.h new file mode 100644 index 00000000..8cef36b7 --- /dev/null +++ b/include/backend/egl.h @@ -0,0 +1,17 @@ +#ifndef WLR_BACKEND_EGL_H +#define WLR_BACKEND_EGL_H + +#include +#include + +struct wlr_egl { + EGLDisplay display; + EGLConfig config; + EGLContext context; +}; + +bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display); +void wlr_egl_free(struct wlr_egl *egl); +EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window); + +#endif diff --git a/include/wlr/common/log.h b/include/wlr/common/log.h index 5b4d5a53..079f989a 100644 --- a/include/wlr/common/log.h +++ b/include/wlr/common/log.h @@ -1,6 +1,7 @@ #ifndef _WLR_COMMON_LOG_H #define _WLR_COMMON_LOG_H #include +#include typedef enum { L_SILENT = 0, diff --git a/session/logind.c b/session/logind.c index 0d8a52b5..052c7454 100644 --- a/session/logind.c +++ b/session/logind.c @@ -200,7 +200,7 @@ static struct wlr_session *logind_session_start(void) { if (!take_control(session)) goto error_bus; - wl_log(L_INFO, "Successfully loaded logind session"); + wlr_log(L_INFO, "Successfully loaded logind session"); session->base.iface = session_logind_iface; return &session->base;