1From 16302ea084be281cbd71bb40ceda7d30b1c44eff Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Fri, 3 Jul 2020 14:53:52 +0800
4Subject: [PATCH 25/95] HACK: pixman-renderer: Support mali egl client and egl
5 buffer attaching
6
7The mali clients requires mali_buffer_sharing extension, and it needs
8lots of hacks to attach a wl_buffer created in that way.
9
10Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
11---
12 libweston/meson.build       |  10 +-
13 libweston/pixman-renderer.c | 427 ++++++++++++++++++++++++++++--------
14 2 files changed, 338 insertions(+), 99 deletions(-)
15
16diff --git a/libweston/meson.build b/libweston/meson.build
17index 313a84f..6a845cc 100644
18--- a/libweston/meson.build
19+++ b/libweston/meson.build
20@@ -73,12 +73,10 @@ srcs_libweston = [
21
22 subdir('desktop')
23
24-if get_option('renderer-gl')
25-	dep_egl = dependency('egl', required: false)
26-	if not dep_egl.found()
27-		error('libweston + gl-renderer requires egl which was not found. Or, you can use \'-Drenderer-gl=false\'.')
28-	endif
29-	deps_libweston += dep_egl
30+dep_egl = dependency('egl', required: false)
31+dep_gbm = dependency('gbm', required: false)
32+if dep_egl.found() and dep_gbm.found()
33+	deps_libweston += [ dep_egl, dep_gbm ]
34 endif
35
36 lib_weston = shared_library(
37diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c
38index 07b7888..7339541 100644
39--- a/libweston/pixman-renderer.c
40+++ b/libweston/pixman-renderer.c
41@@ -47,6 +47,19 @@
42 #include "linux-dmabuf.h"
43 #include "linux-dmabuf-unstable-v1-server-protocol.h"
44
45+#ifdef ENABLE_EGL
46+#include <fcntl.h>
47+#include <sys/stat.h>
48+
49+#include <gbm.h>
50+#include <EGL/egl.h>
51+#include <EGL/eglext.h>
52+#include <GLES2/gl2.h>
53+#include <GLES2/gl2ext.h>
54+#include "shared/platform.h"
55+#include "shared/weston-egl-ext.h"  /* for PFN* stuff */
56+#endif
57+
58 struct pixman_output_state {
59 	pixman_image_t *shadow_image;
60 	pixman_image_t *hw_buffer;
61@@ -75,6 +88,18 @@ struct pixman_renderer {
62 	struct wl_signal destroy_signal;
63
64 	struct weston_drm_format_array supported_formats;
65+
66+#ifdef ENABLE_EGL
67+	PFNEGLBINDWAYLANDDISPLAYWL bind_display;
68+	PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
69+	PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
70+	EGLDisplay egl_display;
71+
72+	int drm_fd;
73+	struct gbm_device *gbm;
74+
75+	bool egl_inited;
76+#endif
77 };
78
79 struct dmabuf_data {
80@@ -82,6 +107,16 @@ struct dmabuf_data {
81 	size_t size;
82 };
83
84+#ifdef ENABLE_EGL
85+/* HACK: For mali_buffer_sharing */
86+struct egl_buffer_info {
87+	int dma_fd;
88+	int width;
89+	int height;
90+	unsigned int stride;
91+};
92+#endif
93+
94 static inline struct pixman_output_state *
95 get_output_state(struct weston_output *output)
96 {
97@@ -669,6 +704,91 @@ pixman_renderer_surface_set_color(struct weston_surface *es,
98 	ps->image = pixman_image_create_solid_fill(&color);
99 }
100
101+static void
102+pixman_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
103+{
104+	struct dmabuf_data *data = dmabuf->user_data;
105+	linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL);
106+
107+	if (data) {
108+		if (data->ptr)
109+			munmap(data->ptr, data->size);
110+
111+		free(data);
112+	}
113+}
114+
115+static bool
116+pixman_renderer_prepare_dmabuf(struct linux_dmabuf_buffer *dmabuf)
117+{
118+	struct dmabuf_attributes *attributes = &dmabuf->attributes;
119+	struct dmabuf_data *data;
120+	size_t total_size, vstride0;
121+	void *ptr;
122+	int i;
123+
124+	data = linux_dmabuf_buffer_get_user_data(dmabuf);
125+	if (data)
126+		return true;
127+
128+	total_size = lseek(attributes->fd[0], 0, SEEK_END);
129+
130+	for (i = 0; i < attributes->n_planes; i++) {
131+		if (attributes->modifier[i] != DRM_FORMAT_MOD_INVALID &&
132+		    attributes->modifier[i] != DRM_FORMAT_MOD_LINEAR)
133+			return false;
134+	}
135+
136+	/* reject all flags we do not recognize or handle */
137+	if (attributes->flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
138+		return false;
139+
140+	if (attributes->n_planes < 0)
141+		return false;
142+
143+	if (attributes->n_planes == 1)
144+		goto out;
145+
146+	vstride0 = (attributes->offset[1] - attributes->offset[0]) /
147+		attributes->stride[0];
148+
149+	for (i = 1; i < attributes->n_planes; i++) {
150+		size_t size = attributes->offset[i] - attributes->offset[i - 1];
151+		size_t vstride = size / attributes->stride[i - 1];
152+
153+		/* not contig */
154+		if (size <= 0 || vstride <= 0 ||
155+		    attributes->offset[i - 1] + size > total_size)
156+			return false;
157+
158+		/* stride unmatched */
159+		if ((vstride != vstride0 && vstride != vstride0 / 2) ||
160+		    (attributes->stride[i] != attributes->stride[0] &&
161+		     attributes->stride[i] != attributes->stride[0] / 2))
162+			return false;
163+	}
164+
165+out:
166+	/* Handle contig dma buffer */
167+
168+	ptr = mmap(NULL, total_size, PROT_READ,
169+		   MAP_SHARED, attributes->fd[0], 0);
170+	if (!ptr)
171+		return false;
172+
173+	data = zalloc(sizeof *data);
174+	if (!data) {
175+		munmap(ptr, total_size);
176+		return false;
177+	}
178+
179+	data->size = total_size;
180+	data->ptr = ptr;
181+	linux_dmabuf_buffer_set_user_data(dmabuf, data,
182+					  pixman_renderer_destroy_dmabuf);
183+	return true;
184+}
185+
186 static void
187 pixman_renderer_attach_dmabuf(struct weston_surface *es,
188 			      struct weston_buffer *buffer,
189@@ -680,14 +800,12 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es,
190 	pixman_format_code_t pixman_format;
191 	size_t vstride;
192
193+	if (!pixman_renderer_prepare_dmabuf(dmabuf))
194+		goto err;
195+
196 	data = linux_dmabuf_buffer_get_user_data(dmabuf);
197-	if (!data || !data->ptr) {
198-		weston_buffer_reference(&ps->buffer_ref, NULL,
199-					BUFFER_WILL_NOT_BE_ACCESSED);
200-		weston_buffer_release_reference(&ps->buffer_release_ref,
201-						NULL);
202-		return;
203-	}
204+	if (!data || !data->ptr)
205+		goto err;
206
207 	buffer->width = attributes->width;
208 	buffer->height = attributes->height;
209@@ -752,11 +870,7 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es,
210 #endif
211 	default:
212 		weston_log("Unsupported dmabuf format\n");
213-		weston_buffer_reference(&ps->buffer_ref, NULL,
214-					BUFFER_WILL_NOT_BE_ACCESSED);
215-		weston_buffer_release_reference(&ps->buffer_release_ref,
216-						NULL);
217-		return;
218+		goto err;
219 	break;
220 	}
221
222@@ -769,6 +883,11 @@ pixman_renderer_attach_dmabuf(struct weston_surface *es,
223 		buffer_state_handle_buffer_destroy;
224 	wl_signal_add(&buffer->destroy_signal,
225 		      &ps->buffer_destroy_listener);
226+	return;
227+err:
228+	weston_buffer_reference(&ps->buffer_ref, NULL,
229+				BUFFER_WILL_NOT_BE_ACCESSED);
230+	weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
231 }
232
233 static void
234@@ -776,7 +895,6 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
235 {
236 	struct pixman_surface_state *ps = get_surface_state(es);
237 	struct wl_shm_buffer *shm_buffer;
238-	struct linux_dmabuf_buffer *dmabuf;
239 	const struct pixel_format_info *pixel_info;
240
241 	weston_buffer_reference(&ps->buffer_ref, buffer,
242@@ -810,17 +928,40 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
243 		return;
244 	}
245
246-	if (buffer->type != WESTON_BUFFER_SHM) {
247-		if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource))) {
248-			pixman_renderer_attach_dmabuf(es, buffer, dmabuf);
249-		} else {
250-			weston_log("unhandled buffer type!\n");
251-			weston_buffer_reference(&ps->buffer_ref, NULL,
252-						BUFFER_WILL_NOT_BE_ACCESSED);
253-			weston_buffer_release_reference(&ps->buffer_release_ref,
254-							NULL);
255-		}
256+	if (buffer->type == WESTON_BUFFER_DMABUF) {
257+		struct linux_dmabuf_buffer *dmabuf =
258+			linux_dmabuf_buffer_get(buffer->resource);
259+		pixman_renderer_attach_dmabuf(es, buffer, dmabuf);
260+		return;
261+	}
262+
263+#ifdef ENABLE_EGL
264+	if (buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) {
265+		struct egl_buffer_info *info;
266+		struct linux_dmabuf_buffer dmabuf = { 0 };
267+		struct dmabuf_attributes *attributes = &dmabuf.attributes;
268+
269+		info = wl_resource_get_user_data(buffer->resource);
270
271+		attributes->format = buffer->pixel_format->format;
272+		attributes->width = buffer->width;
273+		attributes->height = buffer->height;
274+
275+		attributes->n_planes = 1;
276+		attributes->fd[0] = info->dma_fd;
277+		attributes->stride[0] = info->stride;
278+
279+		pixman_renderer_attach_dmabuf(es, buffer, &dmabuf);
280+		return;
281+	}
282+#endif
283+
284+	if (buffer->type != WESTON_BUFFER_SHM) {
285+		weston_log("unhandled buffer type!\n");
286+		weston_buffer_reference(&ps->buffer_ref, NULL,
287+					BUFFER_WILL_NOT_BE_ACCESSED);
288+		weston_buffer_release_reference(&ps->buffer_release_ref,
289+						NULL);
290 		return;
291 	}
292
293@@ -849,6 +990,70 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
294 		      &ps->buffer_destroy_listener);
295 }
296
297+#ifdef ENABLE_EGL
298+static bool
299+pixman_renderer_fill_buffer_info(struct weston_compositor *ec,
300+				 struct weston_buffer *buffer)
301+{
302+	struct pixman_renderer *pr = get_renderer(ec);
303+	struct egl_buffer_info *info;
304+	struct stat s;
305+	EGLint format;
306+	uint32_t fourcc;
307+	EGLint y_inverted;
308+	bool ret = true;
309+
310+	if (!pr->egl_inited)
311+		return false;
312+
313+	info = wl_resource_get_user_data(buffer->resource);
314+	if (!info)
315+		return false;
316+
317+	buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
318+	ret &= pr->query_buffer(pr->egl_display, buffer->legacy_buffer,
319+			        EGL_WIDTH, &buffer->width);
320+	ret &= pr->query_buffer(pr->egl_display, buffer->legacy_buffer,
321+				EGL_HEIGHT, &buffer->height);
322+	ret &= pr->query_buffer(pr->egl_display, buffer->legacy_buffer,
323+				EGL_TEXTURE_FORMAT, &format);
324+	if (!ret) {
325+		weston_log("eglQueryWaylandBufferWL failed\n");
326+		return false;
327+	}
328+
329+	if (fstat(info->dma_fd, &s) < 0 ||
330+	    info->width != buffer->width || info->height != buffer->height)
331+		return false;
332+
333+	switch (format) {
334+	case EGL_TEXTURE_RGB:
335+		fourcc = DRM_FORMAT_XRGB8888;
336+		break;
337+	case EGL_TEXTURE_RGBA:
338+		fourcc = DRM_FORMAT_ARGB8888;
339+		break;
340+	default:
341+		return false;
342+	}
343+
344+	buffer->pixel_format = pixel_format_get_info(fourcc);
345+	assert(buffer->pixel_format);
346+	buffer->format_modifier = DRM_FORMAT_MOD_INVALID;
347+
348+	/* Assume scanout co-ordinate space i.e. (0,0) is top-left
349+	 * if the query fails */
350+	ret = pr->query_buffer(pr->egl_display, buffer->legacy_buffer,
351+			       EGL_WAYLAND_Y_INVERTED_WL, &y_inverted);
352+	if (!ret || y_inverted)
353+		buffer->buffer_origin = ORIGIN_TOP_LEFT;
354+	else
355+		buffer->buffer_origin = ORIGIN_BOTTOM_LEFT;
356+
357+	return true;
358+}
359+#endif
360+
361 static void
362 pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
363 {
364@@ -928,6 +1133,21 @@ pixman_renderer_destroy(struct weston_compositor *ec)
365 {
366 	struct pixman_renderer *pr = get_renderer(ec);
367
368+#ifdef ENABLE_EGL
369+	if (pr->egl_inited) {
370+		if (pr->unbind_display)
371+			pr->unbind_display(pr->egl_display, ec->wl_display);
372+
373+		eglTerminate(pr->egl_display);
374+		eglReleaseThread();
375+
376+		if (pr->gbm)
377+			gbm_device_destroy(pr->gbm);
378+
379+		close(pr->drm_fd);
380+	}
381+#endif
382+
383 	wl_signal_emit(&pr->destroy_signal, pr);
384 	weston_binding_destroy(pr->debug_binding);
385
386@@ -991,80 +1211,11 @@ debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
387 	}
388 }
389
390-static void
391-pixman_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
392-{
393-	struct dmabuf_data *data = dmabuf->user_data;
394-	linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL);
395-
396-	if (data) {
397-		if (data->ptr)
398-			munmap(data->ptr, data->size);
399-
400-		free(data);
401-	}
402-}
403-
404 static bool
405 pixman_renderer_import_dmabuf(struct weston_compositor *ec,
406 			      struct linux_dmabuf_buffer *dmabuf)
407 {
408-	struct dmabuf_attributes *attributes = &dmabuf->attributes;
409-	struct dmabuf_data *data;
410-	size_t total_size, vstride0;
411-	int i;
412-
413-	for (i = 0; i < attributes->n_planes; i++) {
414-		if (attributes->modifier[i] != DRM_FORMAT_MOD_INVALID &&
415-		    attributes->modifier[i] != DRM_FORMAT_MOD_LINEAR)
416-			return false;
417-	}
418-
419-	/* reject all flags we do not recognize or handle */
420-	if (attributes->flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
421-		return false;
422-
423-	if (attributes->n_planes < 0)
424-		return false;
425-
426-	if (attributes->n_planes == 1)
427-		goto out;
428-
429-	total_size = lseek(attributes->fd[0], 0, SEEK_END);
430-	vstride0 = (attributes->offset[1] - attributes->offset[0]) /
431-		attributes->stride[0];
432-
433-	for (i = 1; i < attributes->n_planes; i++) {
434-		size_t size = attributes->offset[i] - attributes->offset[i - 1];
435-		size_t vstride = size / attributes->stride[i - 1];
436-
437-		/* not contig */
438-		if (size <= 0 || vstride <= 0 ||
439-		    attributes->offset[i - 1] + size > total_size)
440-			return false;
441-
442-		/* stride unmatched */
443-		if ((vstride != vstride0 && vstride != vstride0 / 2) ||
444-		    (attributes->stride[i] != attributes->stride[0] &&
445-		     attributes->stride[i] != attributes->stride[0] / 2))
446-			return false;
447-	}
448-
449-out:
450-	/* Handle contig dma buffer */
451-
452-	data = zalloc(sizeof *data);
453-	if (!data)
454-		return false;
455-
456-	linux_dmabuf_buffer_set_user_data(dmabuf, data,
457-					  pixman_renderer_destroy_dmabuf);
458-
459-	data->size = lseek(attributes->fd[0], 0, SEEK_END);
460-
461-	data->ptr = mmap(NULL, data->size, PROT_READ,
462-			 MAP_SHARED, attributes->fd[0], 0);
463-	return data->ptr != MAP_FAILED;
464+	return pixman_renderer_prepare_dmabuf(dmabuf);
465 }
466
467 static const struct weston_drm_format_array *
468@@ -1120,6 +1271,89 @@ out:
469 	return ret;
470 }
471
472+#ifdef ENABLE_EGL
473+static bool
474+pixman_renderer_init_egl(struct pixman_renderer *pr,
475+			 struct weston_compositor *ec)
476+{
477+	PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display;
478+	const char *extensions;
479+
480+	get_platform_display =
481+		(void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
482+	pr->query_buffer =
483+		(void *) eglGetProcAddress("eglQueryWaylandBufferWL");
484+	pr->bind_display =
485+		(void *) eglGetProcAddress("eglBindWaylandDisplayWL");
486+	pr->unbind_display =
487+		(void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
488+
489+	if (!get_platform_display || !pr->query_buffer ||
490+	    !pr->bind_display || !pr->unbind_display) {
491+		weston_log("Failed to get egl proc\n");
492+		return false;
493+	}
494+
495+	pr->drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
496+	if (pr->drm_fd < 0) {
497+		weston_log("Failed to open drm dev\n");
498+		return false;
499+	}
500+
501+	pr->gbm = gbm_create_device(pr->drm_fd);
502+	if (!pr->gbm) {
503+		weston_log("Failed to create gbm device\n");
504+		goto err_close_fd;
505+	}
506+
507+	pr->egl_display = get_platform_display(EGL_PLATFORM_GBM_KHR,
508+					       (void*) pr->gbm, NULL);
509+	if (pr->egl_display == EGL_NO_DISPLAY) {
510+		weston_log("Failed to create egl display\n");
511+		goto err_destroy_gbm;
512+	}
513+
514+	if (!eglInitialize(pr->egl_display, NULL, NULL)) {
515+		weston_log("Failed to initialize egl\n");
516+		goto err_terminate_display;
517+	}
518+
519+	extensions =
520+		(const char *) eglQueryString(pr->egl_display, EGL_EXTENSIONS);
521+	if (!extensions) {
522+		weston_log("Retrieving EGL extension string failed.\n");
523+		goto err_terminate_display;
524+	}
525+
526+	if (!weston_check_egl_extension(extensions,
527+					"EGL_WL_bind_wayland_display")) {
528+		weston_log("Wayland extension not supported.\n");
529+		goto err_terminate_display;
530+	}
531+
532+	if (!eglBindAPI(EGL_OPENGL_ES_API)) {
533+		weston_log("Failed to bind api\n");
534+		goto err_terminate_display;
535+	}
536+
537+	if (!pr->bind_display(pr->egl_display, ec->wl_display))
538+		goto err_terminate_display;
539+
540+	pr->egl_inited = true;
541+	return true;
542+
543+err_terminate_display:
544+	eglTerminate(pr->egl_display);
545+err_destroy_gbm:
546+	gbm_device_destroy(pr->gbm);
547+	pr->gbm = NULL;
548+err_close_fd:
549+	close(pr->drm_fd);
550+	pr->drm_fd = -1;
551+	return false;
552+}
553+#endif
554+
555 WL_EXPORT int
556 pixman_renderer_init(struct weston_compositor *ec)
557 {
558@@ -1141,6 +1375,9 @@ pixman_renderer_init(struct weston_compositor *ec)
559 	renderer->base.destroy = pixman_renderer_destroy;
560 	renderer->base.surface_copy_content =
561 		pixman_renderer_surface_copy_content;
562+#ifdef ENABLE_EGL
563+	renderer->base.fill_buffer_info = pixman_renderer_fill_buffer_info;
564+#endif
565 	ec->renderer = &renderer->base;
566 	ec->capabilities |= WESTON_CAP_ROTATION_ANY;
567 	ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
568@@ -1181,6 +1418,10 @@ pixman_renderer_init(struct weston_compositor *ec)
569 	renderer->base.get_supported_formats =
570 		pixman_renderer_get_supported_formats;
571
572+#ifdef ENABLE_EGL
573+	pixman_renderer_init_egl(renderer, ec);
574+#endif
575+
576 	return 0;
577 }
578
579--
5802.20.1
581
582