| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | #define _POSIX_C_SOURCE 200809L
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include <drm_fourcc.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							| 
									
										
										
										
											2018-11-10 16:06:02 +01:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2018-02-12 21:29:23 +01:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-13 22:49:07 -05:00
										 |  |  | #include <gbm.h>
 | 
					
						
							| 
									
										
										
										
											2017-10-21 14:48:58 +13:00
										 |  |  | #include <wlr/render/egl.h>
 | 
					
						
							| 
									
										
										
										
											2018-02-12 21:29:23 +01:00
										 |  |  | #include <wlr/util/log.h>
 | 
					
						
							| 
									
										
										
										
											2018-11-10 16:06:02 +01:00
										 |  |  | #include <wlr/util/region.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | #include <xf86drm.h>
 | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | static enum wlr_log_importance egl_log_importance_to_wlr(EGLint type) { | 
					
						
							| 
									
										
										
										
											2018-03-21 10:42:43 +01:00
										 |  |  | 	switch (type) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 	case EGL_DEBUG_MSG_CRITICAL_KHR: return WLR_ERROR; | 
					
						
							|  |  |  | 	case EGL_DEBUG_MSG_ERROR_KHR:    return WLR_ERROR; | 
					
						
							|  |  |  | 	case EGL_DEBUG_MSG_WARN_KHR:     return WLR_ERROR; | 
					
						
							|  |  |  | 	case EGL_DEBUG_MSG_INFO_KHR:     return WLR_INFO; | 
					
						
							|  |  |  | 	default:                         return WLR_INFO; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:42:43 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 15:48:38 +02:00
										 |  |  | static const char *egl_error_str(EGLint error) { | 
					
						
							|  |  |  | 	switch (error) { | 
					
						
							|  |  |  | 	case EGL_SUCCESS: | 
					
						
							|  |  |  | 		return "EGL_SUCCESS"; | 
					
						
							|  |  |  | 	case EGL_NOT_INITIALIZED: | 
					
						
							|  |  |  | 		return "EGL_NOT_INITIALIZED"; | 
					
						
							|  |  |  | 	case EGL_BAD_ACCESS: | 
					
						
							|  |  |  | 		return "EGL_BAD_ACCESS"; | 
					
						
							|  |  |  | 	case EGL_BAD_ALLOC: | 
					
						
							|  |  |  | 		return "EGL_BAD_ALLOC"; | 
					
						
							|  |  |  | 	case EGL_BAD_ATTRIBUTE: | 
					
						
							|  |  |  | 		return "EGL_BAD_ATTRIBUTE"; | 
					
						
							|  |  |  | 	case EGL_BAD_CONTEXT: | 
					
						
							|  |  |  | 		return "EGL_BAD_CONTEXT"; | 
					
						
							|  |  |  | 	case EGL_BAD_CONFIG: | 
					
						
							|  |  |  | 		return "EGL_BAD_CONFIG"; | 
					
						
							|  |  |  | 	case EGL_BAD_CURRENT_SURFACE: | 
					
						
							|  |  |  | 		return "EGL_BAD_CURRENT_SURFACE"; | 
					
						
							|  |  |  | 	case EGL_BAD_DISPLAY: | 
					
						
							|  |  |  | 		return "EGL_BAD_DISPLAY"; | 
					
						
							| 
									
										
										
										
											2020-11-17 13:13:18 -07:00
										 |  |  | 	case EGL_BAD_DEVICE_EXT: | 
					
						
							|  |  |  | 		return "EGL_BAD_DEVICE_EXT"; | 
					
						
							| 
									
										
										
										
											2020-06-18 15:48:38 +02:00
										 |  |  | 	case EGL_BAD_SURFACE: | 
					
						
							|  |  |  | 		return "EGL_BAD_SURFACE"; | 
					
						
							|  |  |  | 	case EGL_BAD_MATCH: | 
					
						
							|  |  |  | 		return "EGL_BAD_MATCH"; | 
					
						
							|  |  |  | 	case EGL_BAD_PARAMETER: | 
					
						
							|  |  |  | 		return "EGL_BAD_PARAMETER"; | 
					
						
							|  |  |  | 	case EGL_BAD_NATIVE_PIXMAP: | 
					
						
							|  |  |  | 		return "EGL_BAD_NATIVE_PIXMAP"; | 
					
						
							|  |  |  | 	case EGL_BAD_NATIVE_WINDOW: | 
					
						
							|  |  |  | 		return "EGL_BAD_NATIVE_WINDOW"; | 
					
						
							|  |  |  | 	case EGL_CONTEXT_LOST: | 
					
						
							|  |  |  | 		return "EGL_CONTEXT_LOST"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return "unknown error"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:42:43 +01:00
										 |  |  | static void egl_log(EGLenum error, const char *command, EGLint msg_type, | 
					
						
							|  |  |  | 		EGLLabelKHR thread, EGLLabelKHR obj, const char *msg) { | 
					
						
							| 
									
										
										
										
											2019-09-15 18:52:36 +12:00
										 |  |  | 	_wlr_log(egl_log_importance_to_wlr(msg_type), | 
					
						
							| 
									
										
										
										
											2020-06-18 15:48:38 +02:00
										 |  |  | 		"[EGL] command: %s, error: %s (0x%x), message: \"%s\"", | 
					
						
							|  |  |  | 		command, egl_error_str(error), error, msg); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:42:43 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | static bool check_egl_ext(const char *exts, const char *ext) { | 
					
						
							| 
									
										
										
										
											2018-02-28 18:21:34 +01:00
										 |  |  | 	size_t extlen = strlen(ext); | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 	const char *end = exts + strlen(exts); | 
					
						
							| 
									
										
										
										
											2018-02-28 18:21:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 	while (exts < end) { | 
					
						
							|  |  |  | 		if (*exts == ' ') { | 
					
						
							|  |  |  | 			exts++; | 
					
						
							| 
									
										
										
										
											2018-02-28 18:21:34 +01:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 		size_t n = strcspn(exts, " "); | 
					
						
							|  |  |  | 		if (n == extlen && strncmp(ext, exts, n) == 0) { | 
					
						
							| 
									
										
										
										
											2018-02-28 18:21:34 +01:00
										 |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 		exts += n; | 
					
						
							| 
									
										
										
										
											2018-02-28 18:21:34 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | static void load_egl_proc(void *proc_ptr, const char *name) { | 
					
						
							|  |  |  | 	void *proc = (void *)eglGetProcAddress(name); | 
					
						
							|  |  |  | 	if (proc == NULL) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "eglGetProcAddress(%s) failed", name); | 
					
						
							|  |  |  | 		abort(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*(void **)proc_ptr = proc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | static int get_egl_dmabuf_formats(struct wlr_egl *egl, int **formats); | 
					
						
							|  |  |  | static int get_egl_dmabuf_modifiers(struct wlr_egl *egl, int format, | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 	uint64_t **modifiers, EGLBoolean **external_only); | 
					
						
							| 
									
										
										
										
											2018-03-16 09:11:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | static void init_dmabuf_formats(struct wlr_egl *egl) { | 
					
						
							| 
									
										
										
										
											2018-03-16 09:11:06 +01:00
										 |  |  | 	int *formats; | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 	int formats_len = get_egl_dmabuf_formats(egl, &formats); | 
					
						
							|  |  |  | 	if (formats_len < 0) { | 
					
						
							| 
									
										
										
										
											2018-03-16 09:11:06 +01:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 	for (int i = 0; i < formats_len; i++) { | 
					
						
							|  |  |  | 		uint32_t fmt = formats[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		uint64_t *modifiers; | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 		EGLBoolean *external_only; | 
					
						
							|  |  |  | 		int modifiers_len = | 
					
						
							|  |  |  | 			get_egl_dmabuf_modifiers(egl, fmt, &modifiers, &external_only); | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		if (modifiers_len < 0) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (modifiers_len == 0) { | 
					
						
							| 
									
										
										
										
											2020-11-18 14:53:13 +01:00
										 |  |  | 			wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, | 
					
						
							|  |  |  | 				DRM_FORMAT_MOD_INVALID); | 
					
						
							| 
									
										
										
										
											2020-11-18 14:16:22 +01:00
										 |  |  | 			wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, | 
					
						
							|  |  |  | 				DRM_FORMAT_MOD_INVALID); | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int j = 0; j < modifiers_len; j++) { | 
					
						
							| 
									
										
										
										
											2020-11-18 14:53:13 +01:00
										 |  |  | 			wlr_drm_format_set_add(&egl->dmabuf_texture_formats, fmt, | 
					
						
							|  |  |  | 				modifiers[j]); | 
					
						
							| 
									
										
										
										
											2020-11-18 14:16:22 +01:00
										 |  |  | 			if (!external_only[j]) { | 
					
						
							|  |  |  | 				wlr_drm_format_set_add(&egl->dmabuf_render_formats, fmt, | 
					
						
							|  |  |  | 					modifiers[j]); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		free(modifiers); | 
					
						
							| 
									
										
										
										
											2020-12-10 23:25:16 +01:00
										 |  |  | 		free(external_only); | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	char *str_formats = malloc(formats_len * 5 + 1); | 
					
						
							|  |  |  | 	if (str_formats == NULL) { | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (int i = 0; i < formats_len; i++) { | 
					
						
							|  |  |  | 		snprintf(&str_formats[i*5], (formats_len - i) * 5 + 1, "%.4s ", | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | 			(char*)&formats[i]); | 
					
						
							| 
									
										
										
										
											2018-03-16 09:11:06 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 	wlr_log(WLR_DEBUG, "Supported dmabuf buffer formats: %s", str_formats); | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 	free(str_formats); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2018-03-16 09:11:06 +01:00
										 |  |  | 	free(formats); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display, | 
					
						
							| 
									
										
										
										
											2021-01-09 11:37:21 +01:00
										 |  |  | 		const EGLint *config_attribs) { | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 	struct wlr_egl *egl = calloc(1, sizeof(struct wlr_egl)); | 
					
						
							|  |  |  | 	if (egl == NULL) { | 
					
						
							|  |  |  | 		wlr_log_errno(WLR_ERROR, "Allocation failed"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	const char *client_exts_str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); | 
					
						
							|  |  |  | 	if (client_exts_str == NULL) { | 
					
						
							|  |  |  | 		if (eglGetError() == EGL_BAD_DISPLAY) { | 
					
						
							|  |  |  | 			wlr_log(WLR_ERROR, "EGL_EXT_client_extensions not supported"); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			wlr_log(WLR_ERROR, "Failed to query EGL client extensions"); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	if (!check_egl_ext(client_exts_str, "EGL_EXT_platform_base")) { | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "EGL_EXT_platform_base not supported"); | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	load_egl_proc(&egl->procs.eglGetPlatformDisplayEXT, | 
					
						
							|  |  |  | 		"eglGetPlatformDisplayEXT"); | 
					
						
							|  |  |  | 	load_egl_proc(&egl->procs.eglCreatePlatformWindowSurfaceEXT, | 
					
						
							|  |  |  | 		"eglCreatePlatformWindowSurfaceEXT"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	if (check_egl_ext(client_exts_str, "EGL_KHR_debug")) { | 
					
						
							| 
									
										
										
										
											2019-12-20 16:46:59 +01:00
										 |  |  | 		load_egl_proc(&egl->procs.eglDebugMessageControlKHR, | 
					
						
							|  |  |  | 			"eglDebugMessageControlKHR"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		static const EGLAttrib debug_attribs[] = { | 
					
						
							|  |  |  | 			EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, | 
					
						
							|  |  |  | 			EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, | 
					
						
							|  |  |  | 			EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, | 
					
						
							|  |  |  | 			EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, | 
					
						
							|  |  |  | 			EGL_NONE, | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		egl->procs.eglDebugMessageControlKHR(egl_log, debug_attribs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "Failed to bind to the OpenGL ES API"); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-11 17:45:49 +01:00
										 |  |  | 	egl->display = egl->procs.eglGetPlatformDisplayEXT(platform, | 
					
						
							|  |  |  | 		remote_display, NULL); | 
					
						
							| 
									
										
										
										
											2019-12-20 16:46:59 +01:00
										 |  |  | 	if (egl->display == EGL_NO_DISPLAY) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "Failed to create EGL display"); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EGLint major, minor; | 
					
						
							|  |  |  | 	if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "Failed to initialize EGL"); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	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"); | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2019-12-20 16:46:59 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	if (check_egl_ext(display_exts_str, "EGL_KHR_image_base")) { | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 		egl->exts.image_base_khr = true; | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglCreateImageKHR, "eglCreateImageKHR"); | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglDestroyImageKHR, "eglDestroyImageKHR"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	egl->exts.image_dmabuf_import_ext = | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 		check_egl_ext(display_exts_str, "EGL_EXT_image_dma_buf_import"); | 
					
						
							|  |  |  | 	if (check_egl_ext(display_exts_str, | 
					
						
							|  |  |  | 			"EGL_EXT_image_dma_buf_import_modifiers")) { | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 		egl->exts.image_dmabuf_import_modifiers_ext = true; | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglQueryDmaBufFormatsEXT, | 
					
						
							|  |  |  | 			"eglQueryDmaBufFormatsEXT"); | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglQueryDmaBufModifiersEXT, | 
					
						
							|  |  |  | 			"eglQueryDmaBufModifiersEXT"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	if (check_egl_ext(display_exts_str, "EGL_MESA_image_dma_buf_export")) { | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 		egl->exts.image_dma_buf_export_mesa = true; | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglExportDMABUFImageQueryMESA, | 
					
						
							|  |  |  | 			"eglExportDMABUFImageQueryMESA"); | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglExportDMABUFImageMESA, | 
					
						
							|  |  |  | 			"eglExportDMABUFImageMESA"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	if (check_egl_ext(display_exts_str, "EGL_WL_bind_wayland_display")) { | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 		egl->exts.bind_wayland_display_wl = true; | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglBindWaylandDisplayWL, | 
					
						
							|  |  |  | 			"eglBindWaylandDisplayWL"); | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglUnbindWaylandDisplayWL, | 
					
						
							|  |  |  | 			"eglUnbindWaylandDisplayWL"); | 
					
						
							|  |  |  | 		load_egl_proc(&egl->procs.eglQueryWaylandBufferWL, | 
					
						
							|  |  |  | 			"eglQueryWaylandBufferWL"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 	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"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		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; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		egl->device = (EGLDeviceEXT)device_attrib; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		device_exts_str = | 
					
						
							|  |  |  | 			egl->procs.eglQueryDeviceStringEXT(egl->device, EGL_EXTENSIONS); | 
					
						
							|  |  |  | 		if (device_exts_str == NULL) { | 
					
						
							|  |  |  | 			wlr_log(WLR_ERROR, "eglQueryDeviceStringEXT(EGL_EXTENSIONS) failed"); | 
					
						
							|  |  |  | 			goto error; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		egl->exts.device_drm_ext = | 
					
						
							|  |  |  | 			check_egl_ext(device_exts_str, "EGL_EXT_device_drm"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 13:37:36 +01:00
										 |  |  | 	if (config_attribs != NULL) { | 
					
						
							| 
									
										
										
										
											2021-01-09 11:37:21 +01:00
										 |  |  | 		EGLint matched = 0; | 
					
						
							|  |  |  | 		if (!eglChooseConfig(egl->display, config_attribs, &egl->config, 1, | 
					
						
							|  |  |  | 				&matched)) { | 
					
						
							|  |  |  | 			wlr_log(WLR_ERROR, "eglChooseConfig failed"); | 
					
						
							|  |  |  | 			goto error; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (matched == 0) { | 
					
						
							|  |  |  | 			wlr_log(WLR_ERROR, "Failed to match an EGL config"); | 
					
						
							| 
									
										
										
										
											2020-12-04 13:37:36 +01:00
										 |  |  | 			goto error; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (!check_egl_ext(display_exts_str, "EGL_KHR_no_config_context") && | 
					
						
							|  |  |  | 				!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; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		egl->config = EGL_NO_CONFIG_KHR; | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 	wlr_log(WLR_INFO, "Using EGL %d.%d", (int)major, (int)minor); | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 	wlr_log(WLR_INFO, "Supported EGL client extensions: %s", client_exts_str); | 
					
						
							|  |  |  | 	wlr_log(WLR_INFO, "Supported EGL display extensions: %s", display_exts_str); | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 	if (device_exts_str != NULL) { | 
					
						
							|  |  |  | 		wlr_log(WLR_INFO, "Supported EGL device extensions: %s", device_exts_str); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 	wlr_log(WLR_INFO, "EGL vendor: %s", eglQueryString(egl->display, EGL_VENDOR)); | 
					
						
							| 
									
										
										
										
											2018-01-21 00:06:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 	init_dmabuf_formats(egl); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 	bool ext_context_priority = | 
					
						
							| 
									
										
										
										
											2020-06-10 14:18:04 +02:00
										 |  |  | 		check_egl_ext(display_exts_str, "EGL_IMG_context_priority"); | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	size_t atti = 0; | 
					
						
							|  |  |  | 	EGLint attribs[5]; | 
					
						
							|  |  |  | 	attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; | 
					
						
							|  |  |  | 	attribs[atti++] = 2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 	// On DRM, request a high priority context if possible
 | 
					
						
							|  |  |  | 	bool request_high_priority = ext_context_priority && | 
					
						
							|  |  |  | 		platform == EGL_PLATFORM_GBM_MESA; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 	// Try to reschedule all of our rendering to be completed first. If it
 | 
					
						
							|  |  |  | 	// fails, it will fallback to the default priority (MEDIUM).
 | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 	if (request_high_priority) { | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 		attribs[atti++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG; | 
					
						
							|  |  |  | 		attribs[atti++] = EGL_CONTEXT_PRIORITY_HIGH_IMG; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	attribs[atti++] = EGL_NONE; | 
					
						
							| 
									
										
										
										
											2018-06-08 20:25:36 -04:00
										 |  |  | 	assert(atti <= sizeof(attribs)/sizeof(attribs[0])); | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	egl->context = eglCreateContext(egl->display, egl->config, | 
					
						
							|  |  |  | 		EGL_NO_CONTEXT, attribs); | 
					
						
							|  |  |  | 	if (egl->context == EGL_NO_CONTEXT) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "Failed to create EGL context"); | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 	if (request_high_priority) { | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 		EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; | 
					
						
							|  |  |  | 		eglQueryContext(egl->display, egl->context, | 
					
						
							|  |  |  | 			EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority); | 
					
						
							|  |  |  | 		if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 			wlr_log(WLR_INFO, "Failed to obtain a high priority context"); | 
					
						
							| 
									
										
										
										
											2018-06-08 00:17:45 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 			wlr_log(WLR_DEBUG, "Obtained high priority context"); | 
					
						
							| 
									
										
										
										
											2018-06-03 09:53:03 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 	return egl; | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2017-09-25 19:25:59 -04:00
										 |  |  | 	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:42:43 +01:00
										 |  |  | 	if (egl->display) { | 
					
						
							|  |  |  | 		eglTerminate(egl->display); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 	eglReleaseThread(); | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 	return NULL; | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | void wlr_egl_destroy(struct wlr_egl *egl) { | 
					
						
							| 
									
										
										
										
											2018-03-21 10:42:43 +01:00
										 |  |  | 	if (egl == NULL) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-13 22:49:07 -05:00
										 |  |  | 	if (egl->gbm_device) { | 
					
						
							|  |  |  | 		gbm_device_destroy(egl->gbm_device); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 14:16:22 +01:00
										 |  |  | 	wlr_drm_format_set_finish(&egl->dmabuf_render_formats); | 
					
						
							| 
									
										
										
										
											2020-11-18 14:53:13 +01:00
										 |  |  | 	wlr_drm_format_set_finish(&egl->dmabuf_texture_formats); | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-23 16:17:29 +02:00
										 |  |  | 	eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | 
					
						
							| 
									
										
										
										
											2018-06-05 09:59:26 +01:00
										 |  |  | 	if (egl->wl_display) { | 
					
						
							| 
									
										
										
										
											2018-06-09 18:56:04 +02:00
										 |  |  | 		assert(egl->exts.bind_wayland_display_wl); | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 		egl->procs.eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); | 
					
						
							| 
									
										
										
										
											2017-08-09 21:25:34 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 	eglDestroyContext(egl->display, egl->context); | 
					
						
							|  |  |  | 	eglTerminate(egl->display); | 
					
						
							|  |  |  | 	eglReleaseThread(); | 
					
						
							| 
									
										
										
										
											2021-01-09 12:00:31 +01:00
										 |  |  | 	free(egl); | 
					
						
							| 
									
										
										
										
											2017-08-09 21:25:34 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { | 
					
						
							| 
									
										
										
										
											2018-06-09 18:56:04 +02:00
										 |  |  | 	if (!egl->exts.bind_wayland_display_wl) { | 
					
						
							| 
									
										
										
										
											2017-08-09 21:25:34 +02:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (egl->procs.eglBindWaylandDisplayWL(egl->display, local_display)) { | 
					
						
							| 
									
										
										
										
											2017-08-09 21:25:34 +02:00
										 |  |  | 		egl->wl_display = local_display; | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-10 22:15:37 -04:00
										 |  |  | bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { | 
					
						
							| 
									
										
										
										
											2018-06-09 18:56:04 +02:00
										 |  |  | 	if (!egl->exts.image_base_khr) { | 
					
						
							| 
									
										
										
										
											2017-08-09 21:25:34 +02:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-25 00:42:19 +01:00
										 |  |  | 	if (!image) { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	return egl->procs.eglDestroyImageKHR(egl->display, image); | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	assert(egl->procs.eglCreatePlatformWindowSurfaceEXT); | 
					
						
							|  |  |  | 	EGLSurface surf = egl->procs.eglCreatePlatformWindowSurfaceEXT( | 
					
						
							|  |  |  | 		egl->display, egl->config, window, NULL); | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 	if (surf == EGL_NO_SURFACE) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "Failed to create EGL surface"); | 
					
						
							| 
									
										
										
										
											2017-05-03 17:04:41 +12:00
										 |  |  | 		return EGL_NO_SURFACE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return surf; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-21 00:06:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-09 12:13:35 +01:00
										 |  |  | bool wlr_egl_make_current(struct wlr_egl *egl) { | 
					
						
							|  |  |  | 	if (!eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, | 
					
						
							|  |  |  | 			egl->context)) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "eglMakeCurrent failed"); | 
					
						
							| 
									
										
										
										
											2018-01-21 00:06:35 +01:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-09 22:54:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 11:54:59 +02:00
										 |  |  | bool wlr_egl_unset_current(struct wlr_egl *egl) { | 
					
						
							|  |  |  | 	if (!eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, | 
					
						
							|  |  |  | 			EGL_NO_CONTEXT)) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "eglMakeCurrent failed"); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-01 16:07:50 -04:00
										 |  |  | bool wlr_egl_is_current(struct wlr_egl *egl) { | 
					
						
							|  |  |  | 	return eglGetCurrentContext() == egl->context; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 21:49:44 +00:00
										 |  |  | void wlr_egl_save_context(struct wlr_egl_context *context) { | 
					
						
							|  |  |  | 	context->display = eglGetCurrentDisplay(); | 
					
						
							|  |  |  | 	context->context = eglGetCurrentContext(); | 
					
						
							|  |  |  | 	context->draw_surface = eglGetCurrentSurface(EGL_DRAW); | 
					
						
							|  |  |  | 	context->read_surface = eglGetCurrentSurface(EGL_READ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool wlr_egl_restore_context(struct wlr_egl_context *context) { | 
					
						
							| 
									
										
										
										
											2020-07-13 18:45:57 +00:00
										 |  |  | 	// If the saved context is a null-context, we must use the current
 | 
					
						
							|  |  |  | 	// display instead of the saved display because eglMakeCurrent() can't
 | 
					
						
							|  |  |  | 	// handle EGL_NO_DISPLAY.
 | 
					
						
							|  |  |  | 	EGLDisplay display = context->display == EGL_NO_DISPLAY ? | 
					
						
							|  |  |  | 		eglGetCurrentDisplay() : context->display; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If the current display is also EGL_NO_DISPLAY, we assume that there
 | 
					
						
							|  |  |  | 	// is currently no context set and no action needs to be taken to unset
 | 
					
						
							|  |  |  | 	// the context.
 | 
					
						
							|  |  |  | 	if (display == EGL_NO_DISPLAY) { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return eglMakeCurrent(display, context->draw_surface, | 
					
						
							| 
									
										
										
										
											2020-06-02 21:49:44 +00:00
										 |  |  | 			context->read_surface, context->context); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, | 
					
						
							|  |  |  | 		struct wl_resource *data, EGLint *fmt, int *width, int *height, | 
					
						
							|  |  |  | 		bool *inverted_y) { | 
					
						
							| 
									
										
										
										
											2018-06-09 18:56:04 +02:00
										 |  |  | 	if (!egl->exts.bind_wayland_display_wl || !egl->exts.image_base_khr) { | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglQueryWaylandBufferWL(egl->display, data, | 
					
						
							|  |  |  | 			EGL_TEXTURE_FORMAT, fmt)) { | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	egl->procs.eglQueryWaylandBufferWL(egl->display, data, EGL_WIDTH, width); | 
					
						
							|  |  |  | 	egl->procs.eglQueryWaylandBufferWL(egl->display, data, EGL_HEIGHT, height); | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	EGLint _inverted_y; | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (egl->procs.eglQueryWaylandBufferWL(egl->display, data, | 
					
						
							|  |  |  | 			EGL_WAYLAND_Y_INVERTED_WL, &_inverted_y)) { | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | 		*inverted_y = !!_inverted_y; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		*inverted_y = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const EGLint attribs[] = { | 
					
						
							|  |  |  | 		EGL_WAYLAND_PLANE_WL, 0, | 
					
						
							|  |  |  | 		EGL_NONE, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	return egl->procs.eglCreateImageKHR(egl->display, egl->context, | 
					
						
							|  |  |  | 		EGL_WAYLAND_BUFFER_WL, data, attribs); | 
					
						
							| 
									
										
										
										
											2018-03-31 23:20:00 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 		struct wlr_dmabuf_attributes *attributes, bool *external_only) { | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 	if (!egl->exts.image_base_khr || !egl->exts.image_dmabuf_import_ext) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "dmabuf import extension not present"); | 
					
						
							| 
									
										
										
										
											2018-06-05 09:59:26 +01:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 	bool has_modifier = false; | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// we assume the same way we assumed formats without the import_modifiers
 | 
					
						
							|  |  |  | 	// extension that mod_linear is supported. The special mod mod_invalid
 | 
					
						
							|  |  |  | 	// is sometimes used to signal modifier unawareness which is what we
 | 
					
						
							|  |  |  | 	// have here
 | 
					
						
							|  |  |  | 	if (attributes->modifier != DRM_FORMAT_MOD_INVALID && | 
					
						
							|  |  |  | 			attributes->modifier != DRM_FORMAT_MOD_LINEAR) { | 
					
						
							| 
									
										
										
										
											2018-06-09 18:56:04 +02:00
										 |  |  | 		if (!egl->exts.image_dmabuf_import_modifiers_ext) { | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 			wlr_log(WLR_ERROR, "dmabuf modifiers extension not present"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		has_modifier = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-15 11:22:08 +01:00
										 |  |  | 	unsigned int atti = 0; | 
					
						
							|  |  |  | 	EGLint attribs[50]; | 
					
						
							|  |  |  | 	attribs[atti++] = EGL_WIDTH; | 
					
						
							|  |  |  | 	attribs[atti++] = attributes->width; | 
					
						
							|  |  |  | 	attribs[atti++] = EGL_HEIGHT; | 
					
						
							|  |  |  | 	attribs[atti++] = attributes->height; | 
					
						
							|  |  |  | 	attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; | 
					
						
							|  |  |  | 	attribs[atti++] = attributes->format; | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-15 11:22:08 +01:00
										 |  |  | 	struct { | 
					
						
							|  |  |  | 		EGLint fd; | 
					
						
							|  |  |  | 		EGLint offset; | 
					
						
							|  |  |  | 		EGLint pitch; | 
					
						
							|  |  |  | 		EGLint mod_lo; | 
					
						
							|  |  |  | 		EGLint mod_hi; | 
					
						
							| 
									
										
										
										
											2018-05-29 22:38:00 +01:00
										 |  |  | 	} attr_names[WLR_DMABUF_MAX_PLANES] = { | 
					
						
							| 
									
										
										
										
											2018-03-15 11:22:08 +01:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE0_FD_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE0_OFFSET_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE0_PITCH_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT | 
					
						
							|  |  |  | 		}, { | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE1_FD_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE1_OFFSET_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE1_PITCH_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT | 
					
						
							|  |  |  | 		}, { | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE2_FD_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE2_OFFSET_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE2_PITCH_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT | 
					
						
							|  |  |  | 		}, { | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE3_FD_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE3_OFFSET_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE3_PITCH_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, | 
					
						
							|  |  |  | 			EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i=0; i < attributes->n_planes; i++) { | 
					
						
							|  |  |  | 		attribs[atti++] = attr_names[i].fd; | 
					
						
							|  |  |  | 		attribs[atti++] = attributes->fd[i]; | 
					
						
							|  |  |  | 		attribs[atti++] = attr_names[i].offset; | 
					
						
							|  |  |  | 		attribs[atti++] = attributes->offset[i]; | 
					
						
							|  |  |  | 		attribs[atti++] = attr_names[i].pitch; | 
					
						
							|  |  |  | 		attribs[atti++] = attributes->stride[i]; | 
					
						
							|  |  |  | 		if (has_modifier) { | 
					
						
							|  |  |  | 			attribs[atti++] = attr_names[i].mod_lo; | 
					
						
							| 
									
										
										
										
											2018-05-29 22:38:00 +01:00
										 |  |  | 			attribs[atti++] = attributes->modifier & 0xFFFFFFFF; | 
					
						
							| 
									
										
										
										
											2018-03-15 11:22:08 +01:00
										 |  |  | 			attribs[atti++] = attr_names[i].mod_hi; | 
					
						
							| 
									
										
										
										
											2018-05-29 22:38:00 +01:00
										 |  |  | 			attribs[atti++] = attributes->modifier >> 32; | 
					
						
							| 
									
										
										
										
											2018-03-15 11:22:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	attribs[atti++] = EGL_NONE; | 
					
						
							| 
									
										
										
										
											2018-03-15 11:22:08 +01:00
										 |  |  | 	assert(atti < sizeof(attribs)/sizeof(attribs[0])); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 	EGLImageKHR image = egl->procs.eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		EGL_LINUX_DMA_BUF_EXT, NULL, attribs); | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 	if (image == EGL_NO_IMAGE_KHR) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "eglCreateImageKHR failed"); | 
					
						
							|  |  |  | 		return EGL_NO_IMAGE_KHR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-30 10:56:24 +01:00
										 |  |  | 	*external_only = !wlr_drm_format_set_has(&egl->dmabuf_render_formats, | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 		attributes->format, attributes->modifier); | 
					
						
							|  |  |  | 	return image; | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | static int get_egl_dmabuf_formats(struct wlr_egl *egl, int **formats) { | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 	if (!egl->exts.image_dmabuf_import_ext) { | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		wlr_log(WLR_DEBUG, "DMA-BUF import extension not present"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 	// when we only have the image_dmabuf_import extension we can't query
 | 
					
						
							|  |  |  | 	// which formats are supported. These two are on almost always
 | 
					
						
							|  |  |  | 	// supported; it's the intended way to just try to create buffers.
 | 
					
						
							|  |  |  | 	// Just a guess but better than not supporting dmabufs at all,
 | 
					
						
							|  |  |  | 	// given that the modifiers extension isn't supported everywhere.
 | 
					
						
							|  |  |  | 	if (!egl->exts.image_dmabuf_import_modifiers_ext) { | 
					
						
							|  |  |  | 		static const int fallback_formats[] = { | 
					
						
							|  |  |  | 			DRM_FORMAT_ARGB8888, | 
					
						
							|  |  |  | 			DRM_FORMAT_XRGB8888, | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		static unsigned num = sizeof(fallback_formats) / | 
					
						
							|  |  |  | 			sizeof(fallback_formats[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		*formats = calloc(num, sizeof(int)); | 
					
						
							|  |  |  | 		if (!*formats) { | 
					
						
							|  |  |  | 			wlr_log_errno(WLR_ERROR, "Allocation failed"); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		memcpy(*formats, fallback_formats, num * sizeof(**formats)); | 
					
						
							|  |  |  | 		return num; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 	EGLint num; | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		wlr_log(WLR_ERROR, "Failed to query number of dmabuf formats"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*formats = calloc(num, sizeof(int)); | 
					
						
							|  |  |  | 	if (*formats == NULL) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) { | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		wlr_log(WLR_ERROR, "Failed to query dmabuf format"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		free(*formats); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return num; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | static int get_egl_dmabuf_modifiers(struct wlr_egl *egl, int format, | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 		uint64_t **modifiers, EGLBoolean **external_only) { | 
					
						
							|  |  |  | 	*modifiers = NULL; | 
					
						
							|  |  |  | 	*external_only = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 	if (!egl->exts.image_dmabuf_import_ext) { | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		wlr_log(WLR_DEBUG, "DMA-BUF extension not present"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-06 17:37:15 -04:00
										 |  |  | 	if (!egl->exts.image_dmabuf_import_modifiers_ext) { | 
					
						
							| 
									
										
										
										
											2018-10-12 22:04:12 +02:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 	EGLint num; | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglQueryDmaBufModifiersEXT(egl->display, format, 0, | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 			NULL, NULL, &num)) { | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		wlr_log(WLR_ERROR, "Failed to query dmabuf number of modifiers"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-06 17:37:15 -04:00
										 |  |  | 	if (num == 0) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	*modifiers = calloc(num, sizeof(uint64_t)); | 
					
						
							|  |  |  | 	if (*modifiers == NULL) { | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 		wlr_log_errno(WLR_ERROR, "Allocation failed"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*external_only = calloc(num, sizeof(EGLBoolean)); | 
					
						
							|  |  |  | 	if (*external_only == NULL) { | 
					
						
							|  |  |  | 		wlr_log_errno(WLR_ERROR, "Allocation failed"); | 
					
						
							|  |  |  | 		free(*modifiers); | 
					
						
							|  |  |  | 		*modifiers = NULL; | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglQueryDmaBufModifiersEXT(egl->display, format, num, | 
					
						
							| 
									
										
										
										
											2020-06-05 15:13:32 +02:00
										 |  |  | 			*modifiers, *external_only, &num)) { | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | 		wlr_log(WLR_ERROR, "Failed to query dmabuf modifiers"); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		free(*modifiers); | 
					
						
							| 
									
										
										
										
											2020-12-10 23:25:16 +01:00
										 |  |  | 		free(*external_only); | 
					
						
							| 
									
										
										
										
											2018-02-23 18:45:16 +01:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return num; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-24 23:44:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 14:53:13 +01:00
										 |  |  | const struct wlr_drm_format_set *wlr_egl_get_dmabuf_texture_formats( | 
					
						
							|  |  |  | 		struct wlr_egl *egl) { | 
					
						
							|  |  |  | 	return &egl->dmabuf_texture_formats; | 
					
						
							| 
									
										
										
										
											2019-04-01 19:17:23 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 14:16:22 +01:00
										 |  |  | const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats( | 
					
						
							|  |  |  | 		struct wlr_egl *egl) { | 
					
						
							|  |  |  | 	return &egl->dmabuf_render_formats; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-23 00:03:26 +01:00
										 |  |  | bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image, | 
					
						
							|  |  |  | 		int32_t width, int32_t height, uint32_t flags, | 
					
						
							| 
									
										
										
										
											2018-05-31 12:33:27 +01:00
										 |  |  | 		struct wlr_dmabuf_attributes *attribs) { | 
					
						
							|  |  |  | 	memset(attribs, 0, sizeof(struct wlr_dmabuf_attributes)); | 
					
						
							| 
									
										
										
										
											2018-05-23 00:03:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-17 14:49:18 +01:00
										 |  |  | 	if (!egl->exts.image_dma_buf_export_mesa) { | 
					
						
							| 
									
										
										
										
											2018-05-23 00:03:26 +01:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Only one set of modifiers is returned for all planes
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglExportDMABUFImageQueryMESA(egl->display, image, | 
					
						
							| 
									
										
										
										
											2018-05-31 12:33:27 +01:00
										 |  |  | 			(int *)&attribs->format, &attribs->n_planes, &attribs->modifier)) { | 
					
						
							| 
									
										
										
										
											2018-05-23 00:03:26 +01:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-31 12:33:27 +01:00
										 |  |  | 	if (attribs->n_planes > WLR_DMABUF_MAX_PLANES) { | 
					
						
							| 
									
										
										
										
											2018-07-09 22:49:54 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "EGL returned %d planes, but only %d are supported", | 
					
						
							| 
									
										
										
										
											2018-05-31 12:33:27 +01:00
										 |  |  | 			attribs->n_planes, WLR_DMABUF_MAX_PLANES); | 
					
						
							| 
									
										
										
										
											2018-05-23 00:03:26 +01:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 14:31:33 +01:00
										 |  |  | 	if (!egl->procs.eglExportDMABUFImageMESA(egl->display, image, attribs->fd, | 
					
						
							| 
									
										
										
										
											2018-05-23 00:03:26 +01:00
										 |  |  | 			(EGLint *)attribs->stride, (EGLint *)attribs->offset)) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	attribs->width = width; | 
					
						
							|  |  |  | 	attribs->height = height; | 
					
						
							|  |  |  | 	attribs->flags = flags; | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-25 00:42:19 +01:00
										 |  |  | bool wlr_egl_destroy_surface(struct wlr_egl *egl, EGLSurface surface) { | 
					
						
							|  |  |  | 	if (!surface) { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-22 23:43:15 +02:00
										 |  |  | 	if (eglGetCurrentContext() == egl->context && | 
					
						
							|  |  |  | 			eglGetCurrentSurface(EGL_DRAW) == surface) { | 
					
						
							|  |  |  | 		// Reset the current EGL surface in case it's the one we're destroying,
 | 
					
						
							|  |  |  | 		// otherwise the next wlr_egl_make_current call will result in a
 | 
					
						
							|  |  |  | 		// use-after-free.
 | 
					
						
							| 
									
										
										
										
											2021-01-09 12:13:35 +01:00
										 |  |  | 		wlr_egl_make_current(egl); | 
					
						
							| 
									
										
										
										
											2019-10-22 23:43:15 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-25 00:42:19 +01:00
										 |  |  | 	return eglDestroySurface(egl->display, surface); | 
					
						
							| 
									
										
										
										
											2018-04-24 23:44:43 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:33:30 +01:00
										 |  |  | 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); | 
					
						
							|  |  |  | 	if (devices_len < 0) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "drmGetDevices2 failed"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	drmDevice **devices = calloc(devices_len, sizeof(drmDevice *)); | 
					
						
							|  |  |  | 	if (devices == NULL) { | 
					
						
							|  |  |  | 		wlr_log_errno(WLR_ERROR, "Allocation failed"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	devices_len = drmGetDevices2(flags, devices, devices_len); | 
					
						
							|  |  |  | 	if (devices_len < 0) { | 
					
						
							|  |  |  | 		free(devices); | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "drmGetDevices2 failed"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const drmDevice *match = NULL; | 
					
						
							|  |  |  | 	for (int i = 0; i < devices_len; i++) { | 
					
						
							|  |  |  | 		if (device_has_name(devices[i], name)) { | 
					
						
							|  |  |  | 			match = devices[i]; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	char *render_name = NULL; | 
					
						
							|  |  |  | 	if (match == NULL) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "Cannot find DRM device %s", name); | 
					
						
							|  |  |  | 	} else if (!(match->available_nodes & (1 << DRM_NODE_RENDER))) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, "DRM device %s has no render node", name); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		render_name = strdup(match->nodes[DRM_NODE_RENDER]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < devices_len; i++) { | 
					
						
							|  |  |  | 		drmFreeDevice(&devices[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	free(devices); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return render_name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | int wlr_egl_dup_drm_fd(struct wlr_egl *egl) { | 
					
						
							|  |  |  | 	if (egl->device == EGL_NO_DEVICE_EXT || !egl->exts.device_drm_ext) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const char *primary_name = egl->procs.eglQueryDeviceStringEXT(egl->device, | 
					
						
							|  |  |  | 		EGL_DRM_DEVICE_FILE_EXT); | 
					
						
							|  |  |  | 	if (primary_name == NULL) { | 
					
						
							|  |  |  | 		wlr_log(WLR_ERROR, | 
					
						
							|  |  |  | 			"eglQueryDeviceStringEXT(EGL_DRM_DEVICE_FILE_EXT) failed"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 17:33:30 +01:00
										 |  |  | 	char *render_name = get_render_name(primary_name); | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 	if (render_name == NULL) { | 
					
						
							| 
									
										
										
										
											2020-11-25 17:33:30 +01:00
										 |  |  | 		wlr_log(WLR_ERROR, "Can't find render node name for device %s", | 
					
						
							|  |  |  | 			primary_name); | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int render_fd = open(render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC); | 
					
						
							|  |  |  | 	if (render_fd < 0) { | 
					
						
							| 
									
										
										
										
											2020-11-25 17:33:30 +01:00
										 |  |  | 		wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s", | 
					
						
							|  |  |  | 			render_name); | 
					
						
							|  |  |  | 		free(render_name); | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-25 17:33:30 +01:00
										 |  |  | 	free(render_name); | 
					
						
							| 
									
										
										
										
											2020-06-10 14:26:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return render_fd; | 
					
						
							|  |  |  | } |