1From b53115faf91a004249451513f8da6c5b0434d5da Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Fri, 3 Jul 2020 14:43:49 +0800
4Subject: [PATCH 18/79] pixman-renderer: Support linux dmabuf
5
6NOTE: Only support contig dmabuf.
7
8Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
9---
10 libweston/pixman-renderer.c | 258 +++++++++++++++++++++++++++++++++++-
11 1 file changed, 253 insertions(+), 5 deletions(-)
12
13diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c
14index d7182e7..d5c5422 100644
15--- a/libweston/pixman-renderer.c
16+++ b/libweston/pixman-renderer.c
17@@ -37,8 +37,15 @@
18 #include "pixel-formats.h"
19 #include "shared/helpers.h"
20
21+#include <drm_fourcc.h>
22+#include <string.h>
23+#include <unistd.h>
24+#include <sys/mman.h>
25 #include <linux/input.h>
26
27+#include "linux-dmabuf.h"
28+#include "linux-dmabuf-unstable-v1-server-protocol.h"
29+
30 struct pixman_output_state {
31 	void *shadow_buffer;
32 	pixman_image_t *shadow_image;
33@@ -66,6 +73,13 @@ struct pixman_renderer {
34 	struct weston_binding *debug_binding;
35
36 	struct wl_signal destroy_signal;
37+
38+	struct weston_drm_format_array supported_formats;
39+};
40+
41+struct dmabuf_data {
42+	void *ptr;
43+	size_t size;
44 };
45
46 static inline struct pixman_output_state *
47@@ -353,7 +367,7 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
48 	else
49 		filter = PIXMAN_FILTER_NEAREST;
50
51-	if (ps->buffer_ref.buffer)
52+	if (ps->buffer_ref.buffer && ps->buffer_ref.buffer->shm_buffer)
53 		wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
54
55 	if (ev->alpha < 1.0) {
56@@ -373,7 +387,7 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
57 	if (mask_image)
58 		pixman_image_unref(mask_image);
59
60-	if (ps->buffer_ref.buffer)
61+	if (ps->buffer_ref.buffer && ps->buffer_ref.buffer->shm_buffer)
62 		wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
63
64 	if (pr->repaint_debug)
65@@ -622,11 +636,88 @@ buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
66 	ps->buffer_destroy_listener.notify = NULL;
67 }
68
69+static void
70+pixman_renderer_attach_dmabuf(struct weston_surface *es,
71+			      struct weston_buffer *buffer,
72+			      struct linux_dmabuf_buffer *dmabuf)
73+{
74+	struct pixman_surface_state *ps = get_surface_state(es);
75+	struct dmabuf_attributes *attributes = &dmabuf->attributes;
76+	struct dmabuf_data *data;
77+	pixman_format_code_t pixman_format;
78+	size_t vstride;
79+
80+	data = linux_dmabuf_buffer_get_user_data(dmabuf);
81+	if (!data || !data->ptr) {
82+		weston_buffer_reference(&ps->buffer_ref, NULL);
83+		weston_buffer_release_reference(&ps->buffer_release_ref,
84+						NULL);
85+		return;
86+	}
87+
88+	buffer->width = attributes->width;
89+	buffer->height = attributes->height;
90+
91+	if (attributes->n_planes == 1)
92+		vstride = attributes->height;
93+	else
94+		vstride = (attributes->offset[1] - attributes->offset[0]) /
95+			attributes->stride[0];
96+
97+	switch (attributes->format) {
98+	case DRM_FORMAT_ARGB8888:
99+		pixman_format = PIXMAN_a8r8g8b8;
100+		break;
101+	case DRM_FORMAT_XRGB8888:
102+		pixman_format = PIXMAN_x8r8g8b8;
103+		break;
104+	case DRM_FORMAT_YUYV:
105+		pixman_format = PIXMAN_yuy2;
106+		break;
107+	case DRM_FORMAT_YVU420:
108+		pixman_format = PIXMAN_yv12;
109+		break;
110+#ifdef HAVE_PIXMAN_I420
111+	case DRM_FORMAT_YUV420:
112+		pixman_format = PIXMAN_i420;
113+		break;
114+#endif
115+#ifdef HAVE_PIXMAN_NV12
116+	case DRM_FORMAT_NV12:
117+		pixman_format = PIXMAN_nv12;
118+		break;
119+#endif
120+#ifdef HAVE_PIXMAN_NV16
121+	case DRM_FORMAT_NV16:
122+		pixman_format = PIXMAN_nv16;
123+		break;
124+#endif
125+	default:
126+		weston_log("Unsupported dmabuf format\n");
127+		weston_buffer_reference(&ps->buffer_ref, NULL);
128+		weston_buffer_release_reference(&ps->buffer_release_ref,
129+						NULL);
130+		return;
131+	break;
132+	}
133+
134+	ps->image = pixman_image_create_bits(pixman_format,
135+					     buffer->width, vstride,
136+					     data->ptr + attributes->offset[0],
137+					     attributes->stride[0]);
138+
139+	ps->buffer_destroy_listener.notify =
140+		buffer_state_handle_buffer_destroy;
141+	wl_signal_add(&buffer->destroy_signal,
142+		      &ps->buffer_destroy_listener);
143+}
144+
145 static void
146 pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
147 {
148 	struct pixman_surface_state *ps = get_surface_state(es);
149 	struct wl_shm_buffer *shm_buffer;
150+	struct linux_dmabuf_buffer *dmabuf;
151 	const struct pixel_format_info *pixel_info;
152
153 	weston_buffer_reference(&ps->buffer_ref, buffer);
154@@ -649,9 +740,17 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
155 	shm_buffer = wl_shm_buffer_get(buffer->resource);
156
157 	if (! shm_buffer) {
158-		weston_log("Pixman renderer supports only SHM buffers\n");
159-		weston_buffer_reference(&ps->buffer_ref, NULL);
160-		weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
161+		if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource))) {
162+			pixman_renderer_attach_dmabuf(es, buffer, dmabuf);
163+		} else {
164+			weston_log("unhandled buffer type!\n");
165+			weston_buffer_reference(&ps->buffer_ref, NULL);
166+			weston_buffer_release_reference(&ps->buffer_release_ref,
167+							NULL);
168+			weston_buffer_send_server_error(buffer,
169+				"disconnecting due to unhandled buffer type");
170+		}
171+
172 		return;
173 	}
174
175@@ -750,6 +849,9 @@ pixman_renderer_create_surface(struct weston_surface *surface)
176 	wl_signal_add(&pr->destroy_signal,
177 		      &ps->renderer_destroy_listener);
178
179+	if (surface->buffer_ref.buffer)
180+		pixman_renderer_attach(surface, surface->buffer_ref.buffer);
181+
182 	return 0;
183 }
184
185@@ -780,6 +882,9 @@ pixman_renderer_destroy(struct weston_compositor *ec)
186
187 	wl_signal_emit(&pr->destroy_signal, pr);
188 	weston_binding_destroy(pr->debug_binding);
189+
190+	weston_drm_format_array_fini(&pr->supported_formats);
191+
192 	free(pr);
193
194 	ec->renderer = NULL;
195@@ -853,12 +958,141 @@ debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
196 	}
197 }
198
199+static void
200+pixman_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
201+{
202+	struct dmabuf_data *data = dmabuf->user_data;
203+	linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL);
204+
205+	if (data) {
206+		if (data->ptr)
207+			munmap(data->ptr, data->size);
208+
209+		free(data);
210+	}
211+}
212+
213+static bool
214+pixman_renderer_import_dmabuf(struct weston_compositor *ec,
215+			      struct linux_dmabuf_buffer *dmabuf)
216+{
217+	struct dmabuf_attributes *attributes = &dmabuf->attributes;
218+	struct dmabuf_data *data;
219+	size_t total_size, vstride0;
220+	int i;
221+
222+	for (i = 0; i < attributes->n_planes; i++) {
223+		if (attributes->modifier[i] != DRM_FORMAT_MOD_INVALID)
224+			return false;
225+	}
226+
227+	/* reject all flags we do not recognize or handle */
228+	if (attributes->flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
229+		return false;
230+
231+	if (attributes->n_planes < 0)
232+		return false;
233+
234+	if (attributes->n_planes == 1)
235+		goto out;
236+
237+	total_size = lseek(attributes->fd[0], 0, SEEK_END);
238+	vstride0 = (attributes->offset[1] - attributes->offset[0]) /
239+		attributes->stride[0];
240+
241+	for (i = 1; i < attributes->n_planes; i++) {
242+		size_t size = attributes->offset[i] - attributes->offset[i - 1];
243+		size_t vstride = size / attributes->stride[i - 1];
244+
245+		/* not contig */
246+		if (size <= 0 || vstride <= 0 ||
247+		    attributes->offset[i - 1] + size > total_size)
248+			return false;
249+
250+		/* stride unmatched */
251+		if ((vstride != vstride0 && vstride != vstride0 / 2) ||
252+		    (attributes->stride[i] != attributes->stride[0] &&
253+		     attributes->stride[i] != attributes->stride[0] / 2))
254+			return false;
255+	}
256+
257+out:
258+	/* Handle contig dma buffer */
259+
260+	data = zalloc(sizeof *data);
261+	if (!data)
262+		return false;
263+
264+	linux_dmabuf_buffer_set_user_data(dmabuf, data,
265+					  pixman_renderer_destroy_dmabuf);
266+
267+	data->size = lseek(attributes->fd[0], 0, SEEK_END);
268+
269+	data->ptr = mmap(NULL, data->size, PROT_READ,
270+			 MAP_SHARED, attributes->fd[0], 0);
271+	return data->ptr != MAP_FAILED;
272+}
273+
274+static const struct weston_drm_format_array *
275+pixman_renderer_get_supported_formats(struct weston_compositor *ec)
276+{
277+	struct pixman_renderer *pr = get_renderer(ec);
278+
279+	return &pr->supported_formats;
280+}
281+
282+static int
283+populate_supported_formats(struct weston_compositor *ec,
284+			   struct weston_drm_format_array *supported_formats)
285+{
286+	struct weston_drm_format *fmt;
287+	int i, ret = 0;
288+
289+	/* TODO: support more formats */
290+	static const int formats[] = {
291+		DRM_FORMAT_ARGB8888,
292+		DRM_FORMAT_XRGB8888,
293+		DRM_FORMAT_RGBA8888,
294+		DRM_FORMAT_RGBX8888,
295+		DRM_FORMAT_ABGR8888,
296+		DRM_FORMAT_XBGR8888,
297+		DRM_FORMAT_BGRA8888,
298+		DRM_FORMAT_BGRX8888,
299+		DRM_FORMAT_YUYV,
300+		DRM_FORMAT_YVU420,
301+		DRM_FORMAT_YUV420,
302+		DRM_FORMAT_NV12,
303+		DRM_FORMAT_NV16,
304+	};
305+
306+	int num_formats = ARRAY_LENGTH(formats);
307+
308+	for (i = 0; i < num_formats; i++) {
309+		fmt = weston_drm_format_array_add_format(supported_formats,
310+							 formats[i]);
311+		if (!fmt) {
312+			ret = -1;
313+			goto out;
314+		}
315+
316+		/* Always add DRM_FORMAT_MOD_INVALID, as EGL implementations
317+		 * support implicit modifiers. */
318+		ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
319+		if (ret < 0)
320+			goto out;
321+	}
322+
323+out:
324+	return ret;
325+}
326+
327 WL_EXPORT int
328 pixman_renderer_init(struct weston_compositor *ec)
329 {
330 	struct pixman_renderer *renderer;
331 	const struct pixel_format_info *pixel_info, *info_argb8888, *info_xrgb8888;
332 	unsigned int i, num_formats;
333+	int ret;
334
335 	renderer = zalloc(sizeof *renderer);
336 	if (renderer == NULL)
337@@ -880,6 +1114,15 @@ pixman_renderer_init(struct weston_compositor *ec)
338 	ec->capabilities |= WESTON_CAP_ROTATION_ANY;
339 	ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
340
341+	weston_drm_format_array_init(&renderer->supported_formats);
342+
343+	ret = populate_supported_formats(ec, &renderer->supported_formats);
344+	if (ret < 0) {
345+		weston_drm_format_array_fini(&renderer->supported_formats);
346+		free(renderer);
347+		return -1;
348+	}
349+
350 	renderer->debug_binding =
351 		weston_compositor_add_debug_binding(ec, KEY_R,
352 						    debug_binding, ec);
353@@ -902,6 +1145,11 @@ pixman_renderer_init(struct weston_compositor *ec)
354
355 	wl_signal_init(&renderer->destroy_signal);
356
357+	renderer->base.import_dmabuf = pixman_renderer_import_dmabuf;
358+
359+	renderer->base.get_supported_formats =
360+		pixman_renderer_get_supported_formats;
361+
362 	return 0;
363 }
364
365--
3662.20.1
367
368