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