1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (C) 2016 Red Hat Inc.
5 * Copyright (C) 2017 Intel Corporation
6 * Copyright (C) 2018,2019 DisplayLink (UK) Ltd.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 *
23 * Written by:
24 * Jonas Ådahl <jadahl@gmail.com>
25 * Daniel Stone <daniels@collabora.com>
26 */
27
28 /**
29 * SECTION:meta-wayland-dma-buf
30 * @title: MetaWaylandDmaBuf
31 * @short_description: Handles passing DMA-BUFs in Wayland
32 *
33 * The MetaWaylandDmaBuf namespace contains several objects and functions to
34 * handle DMA-BUF buffers that are passed through from clients in Wayland (e.g.
35 * using the linux_dmabuf_unstable_v1 protocol).
36 */
37
38 #include "config.h"
39
40 #include "wayland/meta-wayland-dma-buf.h"
41
42 #include <drm_fourcc.h>
43
44 #include "backends/meta-backend-private.h"
45 #include "backends/meta-egl-ext.h"
46 #include "backends/meta-egl.h"
47 #include "cogl/cogl-egl.h"
48 #include "cogl/cogl.h"
49 #include "meta/meta-backend.h"
50 #include "wayland/meta-wayland-buffer.h"
51 #include "wayland/meta-wayland-private.h"
52 #include "wayland/meta-wayland-versions.h"
53
54 #ifdef HAVE_NATIVE_BACKEND
55 #include "backends/native/meta-drm-buffer-gbm.h"
56 #include "backends/native/meta-kms-utils.h"
57 #include "backends/native/meta-onscreen-native.h"
58 #include "backends/native/meta-renderer-native.h"
59 #endif
60
61 #include "linux-dmabuf-unstable-v1-server-protocol.h"
62
63 #ifndef DRM_FORMAT_MOD_INVALID
64 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
65 #endif
66
67 #define META_WAYLAND_DMA_BUF_MAX_FDS 4
68
69 struct _MetaWaylandDmaBufBuffer
70 {
71 GObject parent;
72
73 int width;
74 int height;
75 uint32_t drm_format;
76 uint64_t drm_modifier;
77 bool is_y_inverted;
78 int fds[META_WAYLAND_DMA_BUF_MAX_FDS];
79 uint32_t offsets[META_WAYLAND_DMA_BUF_MAX_FDS];
80 uint32_t strides[META_WAYLAND_DMA_BUF_MAX_FDS];
81 };
82
83 G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT);
84
85 static gboolean
meta_wayland_dma_buf_realize_texture(MetaWaylandBuffer * buffer,GError ** error)86 meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
87 GError **error)
88 {
89 MetaBackend *backend = meta_get_backend ();
90 MetaEgl *egl = meta_backend_get_egl (backend);
91 ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
92 CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
93 EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
94 MetaWaylandDmaBufBuffer *dma_buf = buffer->dma_buf.dma_buf;
95 uint32_t n_planes;
96 uint64_t modifiers[META_WAYLAND_DMA_BUF_MAX_FDS];
97 CoglPixelFormat cogl_format;
98 EGLImageKHR egl_image;
99 CoglEglImageFlags flags;
100 CoglTexture2D *texture;
101 MetaDrmFormatBuf format_buf;
102
103 if (buffer->dma_buf.texture)
104 return TRUE;
105
106 switch (dma_buf->drm_format)
107 {
108 /*
109 * NOTE: The cogl_format here is only used for texture color channel
110 * swizzling as compared to COGL_PIXEL_FORMAT_ARGB. It is *not* used
111 * for accessing the buffer memory. EGL will access the buffer
112 * memory according to the DRM fourcc code. Cogl will not mmap
113 * and access the buffer memory at all.
114 */
115 case DRM_FORMAT_XRGB8888:
116 cogl_format = COGL_PIXEL_FORMAT_RGB_888;
117 break;
118 case DRM_FORMAT_XBGR8888:
119 cogl_format = COGL_PIXEL_FORMAT_BGR_888;
120 break;
121 case DRM_FORMAT_ARGB8888:
122 cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
123 break;
124 case DRM_FORMAT_ABGR8888:
125 cogl_format = COGL_PIXEL_FORMAT_ABGR_8888_PRE;
126 break;
127 case DRM_FORMAT_XRGB2101010:
128 cogl_format = COGL_PIXEL_FORMAT_XRGB_2101010;
129 break;
130 case DRM_FORMAT_ARGB2101010:
131 cogl_format = COGL_PIXEL_FORMAT_ARGB_2101010_PRE;
132 break;
133 case DRM_FORMAT_XBGR2101010:
134 cogl_format = COGL_PIXEL_FORMAT_XBGR_2101010;
135 break;
136 case DRM_FORMAT_ABGR2101010:
137 cogl_format = COGL_PIXEL_FORMAT_ABGR_2101010_PRE;
138 break;
139 case DRM_FORMAT_RGB565:
140 cogl_format = COGL_PIXEL_FORMAT_RGB_565;
141 break;
142 case DRM_FORMAT_XBGR16161616F:
143 cogl_format = COGL_PIXEL_FORMAT_XBGR_FP_16161616;
144 break;
145 case DRM_FORMAT_ABGR16161616F:
146 cogl_format = COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE;
147 break;
148 case DRM_FORMAT_XRGB16161616F:
149 cogl_format = COGL_PIXEL_FORMAT_XRGB_FP_16161616;
150 break;
151 case DRM_FORMAT_ARGB16161616F:
152 cogl_format = COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE;
153 break;
154 default:
155 g_set_error (error, G_IO_ERROR,
156 G_IO_ERROR_FAILED,
157 "Unsupported buffer format %d", dma_buf->drm_format);
158 return FALSE;
159 }
160
161 meta_topic (META_DEBUG_WAYLAND,
162 "[dma-buf] wl_buffer@%u DRM format %s -> CoglPixelFormat %s",
163 wl_resource_get_id (meta_wayland_buffer_get_resource (buffer)),
164 meta_drm_format_to_string (&format_buf, dma_buf->drm_format),
165 cogl_pixel_format_to_string (cogl_format));
166
167 for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
168 {
169 if (dma_buf->fds[n_planes] < 0)
170 break;
171
172 modifiers[n_planes] = dma_buf->drm_modifier;
173 }
174
175 egl_image = meta_egl_create_dmabuf_image (egl,
176 egl_display,
177 dma_buf->width,
178 dma_buf->height,
179 dma_buf->drm_format,
180 n_planes,
181 dma_buf->fds,
182 dma_buf->strides,
183 dma_buf->offsets,
184 modifiers,
185 error);
186 if (egl_image == EGL_NO_IMAGE_KHR)
187 return FALSE;
188
189 flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
190 texture = cogl_egl_texture_2d_new_from_image (cogl_context,
191 dma_buf->width,
192 dma_buf->height,
193 cogl_format,
194 egl_image,
195 flags,
196 error);
197
198 meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
199
200 if (!texture)
201 return FALSE;
202
203 buffer->dma_buf.texture = COGL_TEXTURE (texture);
204 buffer->is_y_inverted = dma_buf->is_y_inverted;
205
206 return TRUE;
207 }
208
209 gboolean
meta_wayland_dma_buf_buffer_attach(MetaWaylandBuffer * buffer,CoglTexture ** texture,GError ** error)210 meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
211 CoglTexture **texture,
212 GError **error)
213 {
214 if (!meta_wayland_dma_buf_realize_texture (buffer, error))
215 return FALSE;
216
217 cogl_clear_object (texture);
218 *texture = cogl_object_ref (buffer->dma_buf.texture);
219 return TRUE;
220 }
221
222 #ifdef HAVE_NATIVE_BACKEND
223 static struct gbm_bo *
import_scanout_gbm_bo(MetaWaylandDmaBufBuffer * dma_buf,MetaGpuKms * gpu_kms,int n_planes,gboolean * use_modifier)224 import_scanout_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf,
225 MetaGpuKms *gpu_kms,
226 int n_planes,
227 gboolean *use_modifier)
228 {
229 struct gbm_device *gbm_device;
230
231 gbm_device = meta_gbm_device_from_gpu (gpu_kms);
232
233 if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID ||
234 n_planes > 1 ||
235 dma_buf->offsets[0] > 0)
236 {
237 struct gbm_import_fd_modifier_data import_with_modifier;
238
239 import_with_modifier = (struct gbm_import_fd_modifier_data) {
240 .width = dma_buf->width,
241 .height = dma_buf->height,
242 .format = dma_buf->drm_format,
243 .num_fds = n_planes,
244 .modifier = dma_buf->drm_modifier,
245 };
246 memcpy (import_with_modifier.fds,
247 dma_buf->fds,
248 sizeof (dma_buf->fds));
249 memcpy (import_with_modifier.strides,
250 dma_buf->strides,
251 sizeof (import_with_modifier.strides));
252 memcpy (import_with_modifier.offsets,
253 dma_buf->offsets,
254 sizeof (import_with_modifier.offsets));
255
256 *use_modifier = TRUE;
257 return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD_MODIFIER,
258 &import_with_modifier,
259 GBM_BO_USE_SCANOUT);
260 }
261 else
262 {
263 struct gbm_import_fd_data import_legacy;
264
265 import_legacy = (struct gbm_import_fd_data) {
266 .width = dma_buf->width,
267 .height = dma_buf->height,
268 .format = dma_buf->drm_format,
269 .stride = dma_buf->strides[0],
270 .fd = dma_buf->fds[0],
271 };
272
273 *use_modifier = FALSE;
274 return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD,
275 &import_legacy,
276 GBM_BO_USE_SCANOUT);
277 }
278 }
279 #endif
280
281 CoglScanout *
meta_wayland_dma_buf_try_acquire_scanout(MetaWaylandDmaBufBuffer * dma_buf,CoglOnscreen * onscreen)282 meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
283 CoglOnscreen *onscreen)
284 {
285 #ifdef HAVE_NATIVE_BACKEND
286 MetaBackend *backend = meta_get_backend ();
287 MetaRenderer *renderer = meta_backend_get_renderer (backend);
288 MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
289 MetaDeviceFile *device_file;
290 MetaGpuKms *gpu_kms;
291 int n_planes;
292 uint32_t drm_format;
293 uint64_t drm_modifier;
294 uint32_t stride;
295 struct gbm_bo *gbm_bo;
296 gboolean use_modifier;
297 g_autoptr (GError) error = NULL;
298 MetaDrmBufferGbm *fb;
299
300 for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
301 {
302 if (dma_buf->fds[n_planes] < 0)
303 break;
304 }
305
306 drm_format = dma_buf->drm_format;
307 drm_modifier = dma_buf->drm_modifier;
308 stride = dma_buf->strides[0];
309 if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
310 drm_format,
311 drm_modifier,
312 stride))
313 return NULL;
314
315 device_file = meta_renderer_native_get_primary_device_file (renderer_native);
316 gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
317 gbm_bo = import_scanout_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier);
318 if (!gbm_bo)
319 {
320 g_debug ("Failed to import scanout gbm_bo: %s", g_strerror (errno));
321 return NULL;
322 }
323
324 fb = meta_drm_buffer_gbm_new_take (device_file,
325 gbm_bo,
326 use_modifier,
327 &error);
328 if (!fb)
329 {
330 g_debug ("Failed to create scanout buffer: %s", error->message);
331 gbm_bo_destroy (gbm_bo);
332 return NULL;
333 }
334
335 return COGL_SCANOUT (fb);
336 #else
337 return NULL;
338 #endif
339 }
340
341 static void
buffer_params_add(struct wl_client * client,struct wl_resource * resource,int32_t fd,uint32_t plane_idx,uint32_t offset,uint32_t stride,uint32_t drm_modifier_hi,uint32_t drm_modifier_lo)342 buffer_params_add (struct wl_client *client,
343 struct wl_resource *resource,
344 int32_t fd,
345 uint32_t plane_idx,
346 uint32_t offset,
347 uint32_t stride,
348 uint32_t drm_modifier_hi,
349 uint32_t drm_modifier_lo)
350 {
351 MetaWaylandDmaBufBuffer *dma_buf;
352 uint64_t drm_modifier;
353
354 drm_modifier = ((uint64_t) drm_modifier_hi) << 32;
355 drm_modifier |= ((uint64_t) drm_modifier_lo) & 0xffffffff;
356
357 dma_buf = wl_resource_get_user_data (resource);
358 if (!dma_buf)
359 {
360 wl_resource_post_error (resource,
361 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
362 "params already used");
363 return;
364 }
365
366 if (plane_idx >= META_WAYLAND_DMA_BUF_MAX_FDS)
367 {
368 wl_resource_post_error (resource,
369 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
370 "out-of-bounds plane index %d",
371 plane_idx);
372 return;
373 }
374
375 if (dma_buf->fds[plane_idx] != -1)
376 {
377 wl_resource_post_error (resource,
378 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
379 "plane index %d already set",
380 plane_idx);
381 return;
382 }
383
384 if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID &&
385 dma_buf->drm_modifier != drm_modifier)
386 {
387 wl_resource_post_error (resource,
388 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
389 "mismatching modifier between planes");
390 return;
391 }
392
393 dma_buf->drm_modifier = drm_modifier;
394 dma_buf->fds[plane_idx] = fd;
395 dma_buf->offsets[plane_idx] = offset;
396 dma_buf->strides[plane_idx] = stride;
397 }
398
399 static void
buffer_params_destroy(struct wl_client * client,struct wl_resource * resource)400 buffer_params_destroy (struct wl_client *client,
401 struct wl_resource *resource)
402 {
403 wl_resource_destroy (resource);
404 }
405
406 static void
buffer_params_destructor(struct wl_resource * resource)407 buffer_params_destructor (struct wl_resource *resource)
408 {
409 MetaWaylandDmaBufBuffer *dma_buf;
410
411 /* The user-data for our MetaWaylandBuffer is only valid in between adding
412 * FDs and creating the buffer; once it is created, we free it out into
413 * the wild, where the ref is considered transferred to the wl_buffer. */
414 dma_buf = wl_resource_get_user_data (resource);
415 if (dma_buf)
416 g_object_unref (dma_buf);
417 }
418
419 static void
buffer_destroy(struct wl_client * client,struct wl_resource * resource)420 buffer_destroy (struct wl_client *client,
421 struct wl_resource *resource)
422 {
423 wl_resource_destroy (resource);
424 }
425
426 static const struct wl_buffer_interface dma_buf_buffer_impl =
427 {
428 buffer_destroy,
429 };
430
431 /**
432 * meta_wayland_dma_buf_from_buffer:
433 * @buffer: A #MetaWaylandBuffer object
434 *
435 * Fetches the associated #MetaWaylandDmaBufBuffer from the wayland buffer.
436 * This does not *create* a new object, as this happens in the create_params
437 * request of linux_dmabuf_unstable_v1.
438 *
439 * Returns: (transfer none): The corresponding #MetaWaylandDmaBufBuffer (or
440 * %NULL if it wasn't a dma_buf-based wayland buffer)
441 */
442 MetaWaylandDmaBufBuffer *
meta_wayland_dma_buf_from_buffer(MetaWaylandBuffer * buffer)443 meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer)
444 {
445 if (!buffer->resource)
446 return NULL;
447
448 if (wl_resource_instance_of (buffer->resource, &wl_buffer_interface,
449 &dma_buf_buffer_impl))
450 return wl_resource_get_user_data (buffer->resource);
451
452 return NULL;
453 }
454
455 static void
buffer_params_create_common(struct wl_client * client,struct wl_resource * params_resource,uint32_t buffer_id,int32_t width,int32_t height,uint32_t drm_format,uint32_t flags)456 buffer_params_create_common (struct wl_client *client,
457 struct wl_resource *params_resource,
458 uint32_t buffer_id,
459 int32_t width,
460 int32_t height,
461 uint32_t drm_format,
462 uint32_t flags)
463 {
464 MetaWaylandDmaBufBuffer *dma_buf;
465 MetaWaylandBuffer *buffer;
466 struct wl_resource *buffer_resource;
467 GError *error = NULL;
468
469 dma_buf = wl_resource_get_user_data (params_resource);
470 if (!dma_buf)
471 {
472 wl_resource_post_error (params_resource,
473 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
474 "params already used");
475 return;
476 }
477
478 /* Calling the 'create' method is the point of no return: after that point,
479 * the params object cannot be used. This method must either transfer the
480 * ownership of the MetaWaylandDmaBufBuffer to a MetaWaylandBuffer, or
481 * destroy it. */
482 wl_resource_set_user_data (params_resource, NULL);
483
484 if (dma_buf->fds[0] == -1)
485 {
486 wl_resource_post_error (params_resource,
487 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
488 "no planes added to params");
489 g_object_unref (dma_buf);
490 return;
491 }
492
493 if ((dma_buf->fds[3] >= 0 || dma_buf->fds[2] >= 0) &&
494 (dma_buf->fds[2] == -1 || dma_buf->fds[1] == -1))
495 {
496 wl_resource_post_error (params_resource,
497 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
498 "gap in planes added to params");
499 g_object_unref (dma_buf);
500 return;
501 }
502
503 dma_buf->width = width;
504 dma_buf->height = height;
505 dma_buf->drm_format = drm_format;
506 dma_buf->is_y_inverted = !(flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
507
508 if (flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
509 {
510 wl_resource_post_error (params_resource,
511 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
512 "unknown flags 0x%x supplied", flags);
513 g_object_unref (dma_buf);
514 return;
515 }
516
517 /* Create a new MetaWaylandBuffer wrapping our dmabuf, and immediately try
518 * to realize it, so we can give the client success/fail feedback for the
519 * import. */
520 buffer_resource =
521 wl_resource_create (client, &wl_buffer_interface, 1, buffer_id);
522 wl_resource_set_implementation (buffer_resource, &dma_buf_buffer_impl,
523 dma_buf, NULL);
524 buffer = meta_wayland_buffer_from_resource (buffer_resource);
525
526 meta_wayland_buffer_realize (buffer);
527 if (!meta_wayland_dma_buf_realize_texture (buffer, &error))
528 {
529 if (buffer_id == 0)
530 {
531 zwp_linux_buffer_params_v1_send_failed (params_resource);
532 }
533 else
534 {
535 wl_resource_post_error (params_resource,
536 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
537 "failed to import supplied dmabufs: %s",
538 error ? error->message : "unknown error");
539 }
540
541 /* will unref the MetaWaylandBuffer */
542 wl_resource_destroy (buffer->resource);
543 return;
544 }
545
546 /* If buffer_id is 0, we are using the non-immediate interface, so
547 * need to send a success event with our buffer. */
548 if (buffer_id == 0)
549 zwp_linux_buffer_params_v1_send_created (params_resource,
550 buffer->resource);
551 }
552
553 static void
buffer_params_create(struct wl_client * client,struct wl_resource * params_resource,int32_t width,int32_t height,uint32_t format,uint32_t flags)554 buffer_params_create (struct wl_client *client,
555 struct wl_resource *params_resource,
556 int32_t width,
557 int32_t height,
558 uint32_t format,
559 uint32_t flags)
560 {
561 buffer_params_create_common (client, params_resource, 0, width, height,
562 format, flags);
563 }
564
565 static void
buffer_params_create_immed(struct wl_client * client,struct wl_resource * params_resource,uint32_t buffer_id,int32_t width,int32_t height,uint32_t format,uint32_t flags)566 buffer_params_create_immed (struct wl_client *client,
567 struct wl_resource *params_resource,
568 uint32_t buffer_id,
569 int32_t width,
570 int32_t height,
571 uint32_t format,
572 uint32_t flags)
573 {
574 buffer_params_create_common (client, params_resource, buffer_id, width,
575 height, format, flags);
576 }
577
578 static const struct zwp_linux_buffer_params_v1_interface buffer_params_implementation =
579 {
580 buffer_params_destroy,
581 buffer_params_add,
582 buffer_params_create,
583 buffer_params_create_immed,
584 };
585
586 static void
dma_buf_handle_destroy(struct wl_client * client,struct wl_resource * resource)587 dma_buf_handle_destroy (struct wl_client *client,
588 struct wl_resource *resource)
589 {
590 wl_resource_destroy (resource);
591 }
592
593 static void
dma_buf_handle_create_buffer_params(struct wl_client * client,struct wl_resource * dma_buf_resource,uint32_t params_id)594 dma_buf_handle_create_buffer_params (struct wl_client *client,
595 struct wl_resource *dma_buf_resource,
596 uint32_t params_id)
597 {
598 struct wl_resource *params_resource;
599 MetaWaylandDmaBufBuffer *dma_buf;
600
601 dma_buf = g_object_new (META_TYPE_WAYLAND_DMA_BUF_BUFFER, NULL);
602
603 params_resource =
604 wl_resource_create (client,
605 &zwp_linux_buffer_params_v1_interface,
606 wl_resource_get_version (dma_buf_resource),
607 params_id);
608 wl_resource_set_implementation (params_resource,
609 &buffer_params_implementation,
610 dma_buf,
611 buffer_params_destructor);
612 }
613
614 static const struct zwp_linux_dmabuf_v1_interface dma_buf_implementation =
615 {
616 dma_buf_handle_destroy,
617 dma_buf_handle_create_buffer_params,
618 };
619
620 static gboolean
should_send_modifiers(MetaBackend * backend)621 should_send_modifiers (MetaBackend *backend)
622 {
623 MetaSettings *settings = meta_backend_get_settings (backend);
624
625 if (meta_settings_is_experimental_feature_enabled (
626 settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS))
627 return TRUE;
628
629 #ifdef HAVE_NATIVE_BACKEND
630 if (META_IS_BACKEND_NATIVE (backend))
631 {
632 MetaRenderer *renderer = meta_backend_get_renderer (backend);
633 MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
634 return meta_renderer_native_use_modifiers (renderer_native);
635 }
636 #endif
637
638 return FALSE;
639 }
640
641 static void
send_modifiers(struct wl_resource * resource,uint32_t format)642 send_modifiers (struct wl_resource *resource,
643 uint32_t format)
644 {
645 MetaBackend *backend = meta_get_backend ();
646 MetaEgl *egl = meta_backend_get_egl (backend);
647 ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
648 CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
649 EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
650 EGLint num_modifiers;
651 EGLuint64KHR *modifiers;
652 GError *error = NULL;
653 gboolean ret;
654 int i;
655
656 zwp_linux_dmabuf_v1_send_format (resource, format);
657
658 /* The modifier event was only added in v3; v1 and v2 only have the format
659 * event. */
660 if (wl_resource_get_version (resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
661 return;
662
663 if (!should_send_modifiers (backend))
664 {
665 zwp_linux_dmabuf_v1_send_modifier (resource, format,
666 DRM_FORMAT_MOD_INVALID >> 32,
667 DRM_FORMAT_MOD_INVALID & 0xffffffff);
668 return;
669 }
670
671 /* First query the number of available modifiers, then allocate an array,
672 * then fill the array. */
673 ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format, 0, NULL,
674 NULL, &num_modifiers, NULL);
675 if (!ret)
676 return;
677
678 if (num_modifiers == 0)
679 {
680 zwp_linux_dmabuf_v1_send_modifier (resource, format,
681 DRM_FORMAT_MOD_INVALID >> 32,
682 DRM_FORMAT_MOD_INVALID & 0xffffffff);
683 return;
684 }
685
686 modifiers = g_new0 (uint64_t, num_modifiers);
687 ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format,
688 num_modifiers, modifiers, NULL,
689 &num_modifiers, &error);
690 if (!ret)
691 {
692 g_warning ("Failed to query modifiers for format 0x%" PRIu32 ": %s",
693 format, error ? error->message : "unknown error");
694 g_free (modifiers);
695 return;
696 }
697
698 for (i = 0; i < num_modifiers; i++)
699 {
700 zwp_linux_dmabuf_v1_send_modifier (resource, format,
701 modifiers[i] >> 32,
702 modifiers[i] & 0xffffffff);
703 }
704
705 g_free (modifiers);
706 }
707
708 static void
dma_buf_bind(struct wl_client * client,void * data,uint32_t version,uint32_t id)709 dma_buf_bind (struct wl_client *client,
710 void *data,
711 uint32_t version,
712 uint32_t id)
713 {
714 MetaWaylandCompositor *compositor = data;
715 struct wl_resource *resource;
716
717 resource = wl_resource_create (client, &zwp_linux_dmabuf_v1_interface,
718 version, id);
719 wl_resource_set_implementation (resource, &dma_buf_implementation,
720 compositor, NULL);
721 send_modifiers (resource, DRM_FORMAT_ARGB8888);
722 send_modifiers (resource, DRM_FORMAT_ABGR8888);
723 send_modifiers (resource, DRM_FORMAT_XRGB8888);
724 send_modifiers (resource, DRM_FORMAT_XBGR8888);
725 send_modifiers (resource, DRM_FORMAT_ARGB2101010);
726 send_modifiers (resource, DRM_FORMAT_ABGR2101010);
727 send_modifiers (resource, DRM_FORMAT_XRGB2101010);
728 send_modifiers (resource, DRM_FORMAT_ABGR2101010);
729 send_modifiers (resource, DRM_FORMAT_RGB565);
730 send_modifiers (resource, DRM_FORMAT_ABGR16161616F);
731 send_modifiers (resource, DRM_FORMAT_XBGR16161616F);
732 send_modifiers (resource, DRM_FORMAT_XRGB16161616F);
733 send_modifiers (resource, DRM_FORMAT_ARGB16161616F);
734 }
735
736 /**
737 * meta_wayland_dma_buf_init:
738 * @compositor: The #MetaWaylandCompositor
739 *
740 * Creates the global Wayland object that exposes the linux-dmabuf protocol.
741 *
742 * Returns: Whether the initialization was successful. If this is %FALSE,
743 * clients won't be able to use the linux-dmabuf protocol to pass buffers.
744 */
745 gboolean
meta_wayland_dma_buf_init(MetaWaylandCompositor * compositor)746 meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor)
747 {
748 MetaBackend *backend = meta_get_backend ();
749 MetaEgl *egl = meta_backend_get_egl (backend);
750 ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
751 CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
752 EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
753
754 g_assert (backend && egl && clutter_backend && cogl_context && egl_display);
755
756 if (!meta_egl_has_extensions (egl, egl_display, NULL,
757 "EGL_EXT_image_dma_buf_import_modifiers",
758 NULL))
759 return FALSE;
760
761 if (!wl_global_create (compositor->wayland_display,
762 &zwp_linux_dmabuf_v1_interface,
763 META_ZWP_LINUX_DMABUF_V1_VERSION,
764 compositor,
765 dma_buf_bind))
766 return FALSE;
767
768 return TRUE;
769 }
770
771 static void
meta_wayland_dma_buf_buffer_finalize(GObject * object)772 meta_wayland_dma_buf_buffer_finalize (GObject *object)
773 {
774 MetaWaylandDmaBufBuffer *dma_buf = META_WAYLAND_DMA_BUF_BUFFER (object);
775 int i;
776
777 for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++)
778 {
779 if (dma_buf->fds[i] != -1)
780 close (dma_buf->fds[i]);
781 }
782
783 G_OBJECT_CLASS (meta_wayland_dma_buf_buffer_parent_class)->finalize (object);
784 }
785
786 static void
meta_wayland_dma_buf_buffer_init(MetaWaylandDmaBufBuffer * dma_buf)787 meta_wayland_dma_buf_buffer_init (MetaWaylandDmaBufBuffer *dma_buf)
788 {
789 int i;
790
791 dma_buf->drm_modifier = DRM_FORMAT_MOD_INVALID;
792
793 for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++)
794 dma_buf->fds[i] = -1;
795 }
796
797 static void
meta_wayland_dma_buf_buffer_class_init(MetaWaylandDmaBufBufferClass * klass)798 meta_wayland_dma_buf_buffer_class_init (MetaWaylandDmaBufBufferClass *klass)
799 {
800 GObjectClass *object_class = G_OBJECT_CLASS (klass);
801
802 object_class->finalize = meta_wayland_dma_buf_buffer_finalize;
803 }
804