1/*
2 * Copyright © 2011-2012 Intel Corporation
3 * Copyright © 2012 Collabora, Ltd.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 *    Kristian Høgsberg <krh@bitplanet.net>
27 *    Benjamin Franzke <benjaminfranzke@googlemail.com>
28 */
29
30#include <stdint.h>
31#include <stdlib.h>
32#include <string.h>
33#include <limits.h>
34#include <dlfcn.h>
35#include <errno.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <xf86drm.h>
39#include "drm-uapi/drm_fourcc.h"
40#include <sys/mman.h>
41
42#include "egl_dri2.h"
43#include "loader_dri_helper.h"
44#include "loader.h"
45#include "util/u_vector.h"
46#include "util/anon_file.h"
47#include "eglglobals.h"
48#include "kopper_interface.h"
49
50#include <wayland-egl-backend.h>
51#include <wayland-client.h>
52#include "wayland-drm-client-protocol.h"
53#include "linux-dmabuf-unstable-v1-client-protocol.h"
54
55/*
56 * The index of entries in this table is used as a bitmask in
57 * dri2_dpy->formats.formats_bitmap, which tracks the formats supported
58 * by our server.
59 */
60static const struct dri2_wl_visual {
61   const char *format_name;
62   uint32_t wl_drm_format;
63   uint32_t wl_shm_format;
64   int dri_image_format;
65   /* alt_dri_image_format is a substitute wl_buffer format to use for a
66    * wl-server unsupported dri_image_format, ie. some other dri_image_format in
67    * the table, of the same precision but with different channel ordering, or
68    * __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported.
69    * The code checks if alt_dri_image_format can be used as a fallback for a
70    * dri_image_format for a given wl-server implementation.
71    */
72   int alt_dri_image_format;
73   int bpp;
74   int rgba_shifts[4];
75   unsigned int rgba_sizes[4];
76} dri2_wl_visuals[] = {
77   {
78      "ABGR16F",
79      WL_DRM_FORMAT_ABGR16F, WL_SHM_FORMAT_ABGR16161616F,
80      __DRI_IMAGE_FORMAT_ABGR16161616F, 0, 64,
81      { 0, 16, 32, 48 },
82      { 16, 16, 16, 16 },
83   },
84   {
85      "XBGR16F",
86      WL_DRM_FORMAT_XBGR16F, WL_SHM_FORMAT_XBGR16161616F,
87      __DRI_IMAGE_FORMAT_XBGR16161616F, 0, 64,
88      { 0, 16, 32, -1 },
89      { 16, 16, 16, 0 },
90   },
91   {
92      "XRGB2101010",
93      WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010,
94      __DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32,
95      { 20, 10, 0, -1 },
96      { 10, 10, 10, 0 },
97   },
98   {
99      "ARGB2101010",
100      WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010,
101      __DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32,
102      { 20, 10, 0, 30 },
103      { 10, 10, 10, 2 },
104   },
105   {
106      "XBGR2101010",
107      WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010,
108      __DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32,
109      { 0, 10, 20, -1 },
110      { 10, 10, 10, 0 },
111   },
112   {
113      "ABGR2101010",
114      WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010,
115      __DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32,
116      { 0, 10, 20, 30 },
117      { 10, 10, 10, 2 },
118   },
119   {
120      "XRGB8888",
121      WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888,
122      __DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
123      { 16, 8, 0, -1 },
124      { 8, 8, 8, 0 },
125   },
126   {
127      "ARGB8888",
128      WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888,
129      __DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
130      { 16, 8, 0, 24 },
131      { 8, 8, 8, 8 },
132   },
133   {
134      "ABGR8888",
135      WL_DRM_FORMAT_ABGR8888, WL_SHM_FORMAT_ABGR8888,
136      __DRI_IMAGE_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_NONE, 32,
137      { 0, 8, 16, 24 },
138      { 8, 8, 8, 8 },
139   },
140   {
141      "XBGR8888",
142      WL_DRM_FORMAT_XBGR8888, WL_SHM_FORMAT_XBGR8888,
143      __DRI_IMAGE_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_NONE, 32,
144      { 0, 8, 16, -1 },
145      { 8, 8, 8, 0 },
146   },
147   {
148      "RGB565",
149      WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565,
150      __DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16,
151      { 11, 5, 0, -1 },
152      { 5, 6, 5, 0 },
153   },
154};
155
156static int
157dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy,
158                               const __DRIconfig *config,
159                               bool force_opaque)
160{
161   int shifts[4];
162   unsigned int sizes[4];
163
164   dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
165
166   for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
167      const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i];
168
169      int cmp_rgb_shifts = memcmp(shifts, wl_visual->rgba_shifts,
170                                  3 * sizeof(shifts[0]));
171      int cmp_rgb_sizes = memcmp(sizes, wl_visual->rgba_sizes,
172                                 3 * sizeof(sizes[0]));
173
174      if (cmp_rgb_shifts == 0 && cmp_rgb_sizes == 0 &&
175          wl_visual->rgba_shifts[3] == (force_opaque ? -1 : shifts[3]) &&
176          wl_visual->rgba_sizes[3] == (force_opaque ? 0 : sizes[3])) {
177         return i;
178      }
179   }
180
181   return -1;
182}
183
184static int
185dri2_wl_visual_idx_from_fourcc(uint32_t fourcc)
186{
187   for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
188      /* wl_drm format codes overlap with DRIImage FourCC codes for all formats
189       * we support. */
190      if (dri2_wl_visuals[i].wl_drm_format == fourcc)
191         return i;
192   }
193
194   return -1;
195}
196
197static int
198dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format)
199{
200   for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
201      if (dri2_wl_visuals[i].dri_image_format == dri_image_format)
202         return i;
203   }
204
205   return -1;
206}
207
208static int
209dri2_wl_visual_idx_from_shm_format(uint32_t shm_format)
210{
211   for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
212      if (dri2_wl_visuals[i].wl_shm_format == shm_format)
213         return i;
214   }
215
216   return -1;
217}
218
219bool
220dri2_wl_is_format_supported(void* user_data, uint32_t format)
221{
222   _EGLDisplay *disp = (_EGLDisplay *) user_data;
223   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
224   int j = dri2_wl_visual_idx_from_fourcc(format);
225
226   if (j == -1)
227      return false;
228
229   for (int i = 0; dri2_dpy->driver_configs[i]; i++)
230      if (j == dri2_wl_visual_idx_from_config(dri2_dpy,
231                                              dri2_dpy->driver_configs[i],
232                                              false))
233         return true;
234
235   return false;
236}
237
238static int
239roundtrip(struct dri2_egl_display *dri2_dpy)
240{
241   return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
242}
243
244static void
245wl_buffer_release(void *data, struct wl_buffer *buffer)
246{
247   struct dri2_egl_surface *dri2_surf = data;
248   int i;
249
250   for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
251      if (dri2_surf->color_buffers[i].wl_buffer == buffer)
252         break;
253
254   assert (i < ARRAY_SIZE(dri2_surf->color_buffers));
255
256   if (dri2_surf->color_buffers[i].wl_release) {
257      wl_buffer_destroy(buffer);
258      dri2_surf->color_buffers[i].wl_release = false;
259      dri2_surf->color_buffers[i].wl_buffer = NULL;
260      dri2_surf->color_buffers[i].age = 0;
261   }
262
263   dri2_surf->color_buffers[i].locked = false;
264}
265
266static const struct wl_buffer_listener wl_buffer_listener = {
267   .release = wl_buffer_release
268};
269
270static void
271dri2_wl_formats_fini(struct dri2_wl_formats *formats)
272{
273   unsigned int i;
274
275   for (i = 0; i < formats->num_formats; i++)
276      u_vector_finish(&formats->modifiers[i]);
277
278   free(formats->modifiers);
279   free(formats->formats_bitmap);
280}
281
282static int
283dri2_wl_formats_init(struct dri2_wl_formats *formats)
284{
285   unsigned int i, j;
286
287   /* formats->formats_bitmap tells us if a format in dri2_wl_visuals is present
288    * or not. So we must compute the amount of unsigned int's needed to
289    * represent all the formats of dri2_wl_visuals. We use BITSET_WORDS for
290    * this task. */
291   formats->num_formats = ARRAY_SIZE(dri2_wl_visuals);
292   formats->formats_bitmap = calloc(BITSET_WORDS(formats->num_formats),
293                                    sizeof(*formats->formats_bitmap));
294   if (!formats->formats_bitmap)
295      goto err;
296
297   /* Here we have an array of u_vector's to store the modifiers supported by
298    * each format in the bitmask. */
299   formats->modifiers = calloc(formats->num_formats,
300                               sizeof(*formats->modifiers));
301   if (!formats->modifiers)
302      goto err_modifier;
303
304   for (i = 0; i < formats->num_formats; i++)
305      if (!u_vector_init_pow2(&formats->modifiers[i], 4, sizeof(uint64_t))) {
306         j = i;
307         goto err_vector_init;
308      }
309
310   return 0;
311
312err_vector_init:
313   for (i = 0; i < j; i++)
314      u_vector_finish(&formats->modifiers[i]);
315   free(formats->modifiers);
316err_modifier:
317   free(formats->formats_bitmap);
318err:
319   _eglError(EGL_BAD_ALLOC, "dri2_wl_formats_init");
320   return -1;
321}
322
323static void
324dmabuf_feedback_format_table_fini(struct dmabuf_feedback_format_table *format_table)
325{
326   if (format_table->data && format_table->data != MAP_FAILED)
327      munmap(format_table->data, format_table->size);
328}
329
330static void
331dmabuf_feedback_format_table_init(struct dmabuf_feedback_format_table *format_table)
332{
333   memset(format_table, 0, sizeof(*format_table));
334}
335
336static void
337dmabuf_feedback_tranche_fini(struct dmabuf_feedback_tranche *tranche)
338{
339   dri2_wl_formats_fini(&tranche->formats);
340}
341
342static int
343dmabuf_feedback_tranche_init(struct dmabuf_feedback_tranche *tranche)
344{
345   memset(tranche, 0, sizeof(*tranche));
346
347   if (dri2_wl_formats_init(&tranche->formats) < 0)
348      return -1;
349
350   return 0;
351}
352
353static void
354dmabuf_feedback_fini(struct dmabuf_feedback *dmabuf_feedback)
355{
356   dmabuf_feedback_tranche_fini(&dmabuf_feedback->pending_tranche);
357
358   util_dynarray_foreach(&dmabuf_feedback->tranches,
359                         struct dmabuf_feedback_tranche, tranche)
360      dmabuf_feedback_tranche_fini(tranche);
361   util_dynarray_fini(&dmabuf_feedback->tranches);
362
363   dmabuf_feedback_format_table_fini(&dmabuf_feedback->format_table);
364}
365
366static int
367dmabuf_feedback_init(struct dmabuf_feedback *dmabuf_feedback)
368{
369   memset(dmabuf_feedback, 0, sizeof(*dmabuf_feedback));
370
371   if (dmabuf_feedback_tranche_init(&dmabuf_feedback->pending_tranche) < 0)
372      return -1;
373
374   util_dynarray_init(&dmabuf_feedback->tranches, NULL);
375
376   dmabuf_feedback_format_table_init(&dmabuf_feedback->format_table);
377
378   return 0;
379}
380
381static void
382resize_callback(struct wl_egl_window *wl_win, void *data)
383{
384   struct dri2_egl_surface *dri2_surf = data;
385   struct dri2_egl_display *dri2_dpy =
386      dri2_egl_display(dri2_surf->base.Resource.Display);
387
388   if (dri2_surf->base.Width == wl_win->width &&
389       dri2_surf->base.Height == wl_win->height)
390      return;
391
392   dri2_surf->resized = true;
393
394   /* Update the surface size as soon as native window is resized; from user
395    * pov, this makes the effect that resize is done immediately after native
396    * window resize, without requiring to wait until the first draw.
397    *
398    * A more detailed and lengthy explanation can be found at
399    * https://lists.freedesktop.org/archives/mesa-dev/2018-June/196474.html
400    */
401   if (!dri2_surf->back) {
402      dri2_surf->base.Width = wl_win->width;
403      dri2_surf->base.Height = wl_win->height;
404   }
405   dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
406}
407
408static void
409destroy_window_callback(void *data)
410{
411   struct dri2_egl_surface *dri2_surf = data;
412   dri2_surf->wl_win = NULL;
413}
414
415static struct wl_surface *
416get_wl_surface_proxy(struct wl_egl_window *window)
417{
418    /* Version 3 of wl_egl_window introduced a version field at the same
419     * location where a pointer to wl_surface was stored. Thus, if
420     * window->version is dereferenceable, we've been given an older version of
421     * wl_egl_window, and window->version points to wl_surface */
422   if (_eglPointerIsDereferencable((void *)(window->version))) {
423      return wl_proxy_create_wrapper((void *)(window->version));
424   }
425   return wl_proxy_create_wrapper(window->surface);
426}
427
428static void
429surface_dmabuf_feedback_format_table(void *data,
430                                     struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
431                                     int32_t fd, uint32_t size)
432{
433   struct dri2_egl_surface *dri2_surf = data;
434   struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
435
436   feedback->format_table.size = size;
437   feedback->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
438
439   close(fd);
440}
441
442static void
443surface_dmabuf_feedback_main_device(void *data,
444                                    struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
445                                    struct wl_array *device)
446{
447   struct dri2_egl_surface *dri2_surf = data;
448   struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
449
450   memcpy(&feedback->main_device, device->data, sizeof(feedback->main_device));
451
452   /* Compositors may support switching render devices and change the main
453    * device of the dma-buf feedback. In this case, when we reallocate the
454    * buffers of the surface we must ensure that it is not allocated in memory
455    * that is only visible to the GPU that EGL is using, as the compositor will
456    * have to import them to the render device it is using.
457    *
458    * TODO: we still don't know how to allocate such buffers.
459    */
460   if (dri2_surf->dmabuf_feedback.main_device != 0 &&
461       (feedback->main_device != dri2_surf->dmabuf_feedback.main_device))
462      dri2_surf->compositor_using_another_device = true;
463   else
464      dri2_surf->compositor_using_another_device = false;
465}
466
467static void
468surface_dmabuf_feedback_tranche_target_device(void *data,
469                                              struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
470                                              struct wl_array *device)
471{
472   struct dri2_egl_surface *dri2_surf = data;
473   struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
474
475   memcpy(&feedback->pending_tranche.target_device, device->data,
476          sizeof(feedback->pending_tranche.target_device));
477}
478
479static void
480surface_dmabuf_feedback_tranche_flags(void *data,
481                                      struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
482                                      uint32_t flags)
483{
484   struct dri2_egl_surface *dri2_surf = data;
485   struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
486
487   feedback->pending_tranche.flags = flags;
488}
489
490static void
491surface_dmabuf_feedback_tranche_formats(void *data,
492                                        struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
493                                        struct wl_array *indices)
494{
495   struct dri2_egl_surface *dri2_surf = data;
496   struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
497   uint64_t *modifier_ptr, modifier;
498   uint32_t format;
499   uint16_t *index;
500   int visual_idx;
501
502   /* Compositor may advertise or not a format table. If it does, we use it.
503    * Otherwise, we steal the most recent advertised format table. If we don't have
504    * a most recent advertised format table, compositor did something wrong. */
505   if (feedback->format_table.data == NULL) {
506      feedback->format_table = dri2_surf->dmabuf_feedback.format_table;
507      dmabuf_feedback_format_table_init(&dri2_surf->dmabuf_feedback.format_table);
508   }
509   if (feedback->format_table.data == MAP_FAILED) {
510      _eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table "
511                            "so we won't be able to use this batch of dma-buf "
512                            "feedback events.");
513      return;
514   }
515   if (feedback->format_table.data == NULL) {
516      _eglLog(_EGL_WARNING, "wayland-egl: compositor didn't advertise a format "
517                            "table, so we won't be able to use this batch of dma-buf "
518                            "feedback events.");
519      return;
520   }
521
522   wl_array_for_each(index, indices) {
523      format = feedback->format_table.data[*index].format;
524      modifier = feedback->format_table.data[*index].modifier;
525
526      /* Skip formats that are not the one the surface is already using. We
527       * can't switch to another format. */
528      if (format != dri2_surf->format)
529         continue;
530
531      /* We are sure that the format is supported because of the check above. */
532      visual_idx = dri2_wl_visual_idx_from_fourcc(format);
533      assert(visual_idx != -1);
534
535      BITSET_SET(feedback->pending_tranche.formats.formats_bitmap, visual_idx);
536      modifier_ptr =
537         u_vector_add(&feedback->pending_tranche.formats.modifiers[visual_idx]);
538      if (modifier_ptr)
539         *modifier_ptr = modifier;
540   }
541}
542
543static void
544surface_dmabuf_feedback_tranche_done(void *data,
545                                     struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
546{
547   struct dri2_egl_surface *dri2_surf = data;
548   struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
549
550   /* Add tranche to array of tranches. */
551   util_dynarray_append(&feedback->tranches, struct dmabuf_feedback_tranche,
552                        feedback->pending_tranche);
553
554   dmabuf_feedback_tranche_init(&feedback->pending_tranche);
555}
556
557static void
558surface_dmabuf_feedback_done(void *data,
559                             struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
560{
561   struct dri2_egl_surface *dri2_surf = data;
562
563   /* The dma-buf feedback protocol states that surface dma-buf feedback should
564    * be sent by the compositor only if its buffers are using a suboptimal pair
565    * of format and modifier. We can't change the buffer format, but we can
566    * reallocate with another modifier. So we raise this flag in order to force
567    * buffer reallocation based on the dma-buf feedback sent. */
568   dri2_surf->received_dmabuf_feedback = true;
569
570   dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
571   dri2_surf->dmabuf_feedback = dri2_surf->pending_dmabuf_feedback;
572   dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback);
573}
574
575static const struct zwp_linux_dmabuf_feedback_v1_listener
576surface_dmabuf_feedback_listener = {
577   .format_table = surface_dmabuf_feedback_format_table,
578   .main_device = surface_dmabuf_feedback_main_device,
579   .tranche_target_device = surface_dmabuf_feedback_tranche_target_device,
580   .tranche_flags = surface_dmabuf_feedback_tranche_flags,
581   .tranche_formats = surface_dmabuf_feedback_tranche_formats,
582   .tranche_done = surface_dmabuf_feedback_tranche_done,
583   .done = surface_dmabuf_feedback_done,
584};
585
586/**
587 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
588 */
589static _EGLSurface *
590dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
591                              void *native_window, const EGLint *attrib_list)
592{
593   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
594   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
595   struct wl_egl_window *window = native_window;
596   struct dri2_egl_surface *dri2_surf;
597   struct zwp_linux_dmabuf_v1 *dmabuf_wrapper;
598   int visual_idx;
599   const __DRIconfig *config;
600
601   if (!window) {
602      _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
603      return NULL;
604   }
605
606   if (window->driver_private) {
607      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
608      return NULL;
609   }
610
611   dri2_surf = calloc(1, sizeof *dri2_surf);
612   if (!dri2_surf) {
613      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
614      return NULL;
615   }
616
617   if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
618                          attrib_list, false, native_window))
619      goto cleanup_surf;
620
621   config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
622                                dri2_surf->base.GLColorspace);
623
624   if (!config) {
625      _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
626      goto cleanup_surf;
627   }
628
629   dri2_surf->base.Width = window->width;
630   dri2_surf->base.Height = window->height;
631
632#ifndef NDEBUG
633   /* Enforce that every visual has an opaque variant (requirement to support
634    * EGL_EXT_present_opaque)
635    */
636   for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
637      const struct dri2_wl_visual *transparent_visual = &dri2_wl_visuals[i];
638      if (transparent_visual->rgba_sizes[3] == 0) {
639         continue;
640      }
641
642      bool found_opaque_equivalent = false;
643      for (unsigned int j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) {
644         const struct dri2_wl_visual *opaque_visual = &dri2_wl_visuals[j];
645         if (opaque_visual->rgba_sizes[3] != 0) {
646            continue;
647         }
648
649         int cmp_rgb_shifts = memcmp(transparent_visual->rgba_shifts,
650                                     opaque_visual->rgba_shifts,
651                                     3 * sizeof(opaque_visual->rgba_shifts[0]));
652         int cmp_rgb_sizes = memcmp(transparent_visual->rgba_sizes,
653                                    opaque_visual->rgba_sizes,
654                                    3 * sizeof(opaque_visual->rgba_sizes[0]));
655
656         if (cmp_rgb_shifts == 0 && cmp_rgb_sizes == 0) {
657            found_opaque_equivalent = true;
658            break;
659         }
660      }
661
662      assert(found_opaque_equivalent);
663   }
664#endif
665
666   visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config,
667                                               dri2_surf->base.PresentOpaque);
668   assert(visual_idx != -1);
669
670   if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {
671      dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format;
672   } else {
673      assert(dri2_dpy->wl_shm);
674      dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format;
675   }
676
677   dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
678   if (!dri2_surf->wl_queue) {
679      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
680      goto cleanup_surf;
681   }
682
683   if (dri2_dpy->wl_drm) {
684      dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);
685      if (!dri2_surf->wl_drm_wrapper) {
686         _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
687         goto cleanup_queue;
688      }
689      wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,
690                         dri2_surf->wl_queue);
691   }
692
693   dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
694   if (!dri2_surf->wl_dpy_wrapper) {
695      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
696      goto cleanup_drm;
697   }
698   wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,
699                      dri2_surf->wl_queue);
700
701   dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window);
702   if (!dri2_surf->wl_surface_wrapper) {
703      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
704      goto cleanup_dpy_wrapper;
705   }
706   wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
707                      dri2_surf->wl_queue);
708
709   if (dri2_dpy->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >=
710                              ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION) {
711      dmabuf_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dmabuf);
712      if (!dmabuf_wrapper) {
713         _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
714         goto cleanup_surf_wrapper;
715      }
716      wl_proxy_set_queue((struct wl_proxy *)dmabuf_wrapper,
717                         dri2_surf->wl_queue);
718      dri2_surf->wl_dmabuf_feedback =
719         zwp_linux_dmabuf_v1_get_surface_feedback(dmabuf_wrapper,
720                                                  dri2_surf->wl_surface_wrapper);
721      wl_proxy_wrapper_destroy(dmabuf_wrapper);
722
723      zwp_linux_dmabuf_feedback_v1_add_listener(dri2_surf->wl_dmabuf_feedback,
724                                                &surface_dmabuf_feedback_listener,
725                                                dri2_surf);
726
727      if (dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback) < 0) {
728         zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback);
729         goto cleanup_surf_wrapper;
730      }
731      if (dmabuf_feedback_init(&dri2_surf->dmabuf_feedback) < 0) {
732         dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback);
733         zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback);
734         goto cleanup_surf_wrapper;
735      }
736
737      if (roundtrip(dri2_dpy) < 0)
738         goto cleanup_dmabuf_feedback;
739   }
740
741   dri2_surf->wl_win = window;
742   dri2_surf->wl_win->driver_private = dri2_surf;
743   dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
744   if (dri2_dpy->flush)
745      dri2_surf->wl_win->resize_callback = resize_callback;
746
747   if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
748       goto cleanup_dmabuf_feedback;
749
750   dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
751
752   return &dri2_surf->base;
753
754 cleanup_dmabuf_feedback:
755   if (dri2_surf->wl_dmabuf_feedback) {
756      zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback);
757      dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
758      dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback);
759   }
760 cleanup_surf_wrapper:
761   wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
762 cleanup_dpy_wrapper:
763   wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
764 cleanup_drm:
765   if (dri2_surf->wl_drm_wrapper)
766      wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
767 cleanup_queue:
768   wl_event_queue_destroy(dri2_surf->wl_queue);
769 cleanup_surf:
770   free(dri2_surf);
771
772   return NULL;
773}
774
775static _EGLSurface *
776dri2_wl_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
777                              void *native_window, const EGLint *attrib_list)
778{
779   /* From the EGL_EXT_platform_wayland spec, version 3:
780    *
781    *   It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
782    *   that belongs to Wayland. Any such call fails and generates
783    *   EGL_BAD_PARAMETER.
784    */
785   _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
786             "Wayland");
787   return NULL;
788}
789
790/**
791 * Called via eglDestroySurface(), drv->DestroySurface().
792 */
793static EGLBoolean
794dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
795{
796   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
797   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
798
799   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
800
801   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
802      if (dri2_surf->color_buffers[i].wl_buffer)
803         wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
804      if (dri2_surf->color_buffers[i].dri_image)
805         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
806      if (dri2_surf->color_buffers[i].linear_copy)
807         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
808      if (dri2_surf->color_buffers[i].data)
809         munmap(dri2_surf->color_buffers[i].data,
810                dri2_surf->color_buffers[i].data_size);
811   }
812
813   if (dri2_dpy->dri2)
814      dri2_egl_surface_free_local_buffers(dri2_surf);
815
816   if (dri2_surf->throttle_callback)
817      wl_callback_destroy(dri2_surf->throttle_callback);
818
819   if (dri2_surf->wl_win) {
820      dri2_surf->wl_win->driver_private = NULL;
821      dri2_surf->wl_win->resize_callback = NULL;
822      dri2_surf->wl_win->destroy_window_callback = NULL;
823   }
824
825   wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
826   wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
827   if (dri2_surf->wl_drm_wrapper)
828      wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
829   if (dri2_surf->wl_dmabuf_feedback) {
830      zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback);
831      dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
832      dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback);
833   }
834   wl_event_queue_destroy(dri2_surf->wl_queue);
835
836   dri2_fini_surface(surf);
837   free(surf);
838
839   return EGL_TRUE;
840}
841
842static EGLBoolean
843dri2_wl_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
844{
845   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
846   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
847
848   if (dri2_dpy->kopper)
849      dri2_dpy->kopper->setSwapInterval(dri2_surf->dri_drawable, interval);
850
851   return EGL_TRUE;
852}
853
854static void
855dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
856{
857   struct dri2_egl_display *dri2_dpy =
858      dri2_egl_display(dri2_surf->base.Resource.Display);
859
860   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
861      if (dri2_surf->color_buffers[i].wl_buffer) {
862         if (dri2_surf->color_buffers[i].locked) {
863            dri2_surf->color_buffers[i].wl_release = true;
864         } else {
865            wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
866            dri2_surf->color_buffers[i].wl_buffer = NULL;
867         }
868      }
869      if (dri2_surf->color_buffers[i].dri_image)
870         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
871      if (dri2_surf->color_buffers[i].linear_copy)
872         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
873      if (dri2_surf->color_buffers[i].data)
874         munmap(dri2_surf->color_buffers[i].data,
875                dri2_surf->color_buffers[i].data_size);
876
877      dri2_surf->color_buffers[i].dri_image = NULL;
878      dri2_surf->color_buffers[i].linear_copy = NULL;
879      dri2_surf->color_buffers[i].data = NULL;
880      dri2_surf->color_buffers[i].age = 0;
881   }
882
883   if (dri2_dpy->dri2)
884      dri2_egl_surface_free_local_buffers(dri2_surf);
885}
886
887static void
888create_dri_image_diff_gpu(struct dri2_egl_surface *dri2_surf,
889                          unsigned int linear_dri_image_format, uint32_t use_flags)
890{
891   struct dri2_egl_display *dri2_dpy =
892      dri2_egl_display(dri2_surf->base.Resource.Display);
893   uint64_t linear_mod;
894
895   /* The LINEAR modifier should be a perfect alias of the LINEAR use flag */
896   linear_mod = DRM_FORMAT_MOD_LINEAR;
897
898   dri2_surf->back->linear_copy =
899      loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
900                              dri2_surf->base.Width,
901                              dri2_surf->base.Height,
902                              linear_dri_image_format,
903                              use_flags | __DRI_IMAGE_USE_LINEAR,
904                              &linear_mod, 1, NULL);
905}
906
907static void
908create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf,
909                                      unsigned int dri_image_format, uint32_t use_flags)
910{
911   struct dri2_egl_display *dri2_dpy =
912      dri2_egl_display(dri2_surf->base.Resource.Display);
913   int visual_idx;
914   uint64_t *modifiers;
915   unsigned int num_modifiers;
916   uint32_t flags;
917
918   /* We don't have valid dma-buf feedback, so return */
919   if (dri2_surf->dmabuf_feedback.main_device == 0)
920      return;
921
922   visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
923   assert(visual_idx != -1);
924
925   /* Iterates through the dma-buf feedback to pick a new set of modifiers. The
926    * tranches are sent in descending order of preference by the compositor, so
927    * the first set that we can pick is the best one. For now we still can't
928    * specify the target device in order to make the render device try its best
929    * to allocate memory that can be directly scanned out by the KMS device. But
930    * in the future this may change (newer versions of
931    * createImageWithModifiers). Also, we are safe to pick modifiers from
932    * tranches whose target device differs from the main device, as compositors
933    * do not expose (in dma-buf feedback tranches) formats/modifiers that are
934    * incompatible with the main device. */
935   util_dynarray_foreach(&dri2_surf->dmabuf_feedback.tranches,
936                         struct dmabuf_feedback_tranche, tranche) {
937      /* Ignore tranches that do not contain dri2_surf->format */
938      if (!BITSET_TEST(tranche->formats.formats_bitmap, visual_idx))
939         continue;
940      modifiers = u_vector_tail(&tranche->formats.modifiers[visual_idx]);
941      num_modifiers = u_vector_length(&tranche->formats.modifiers[visual_idx]);
942
943      /* For the purposes of this function, an INVALID modifier on
944       * its own means the modifiers aren't supported. */
945      if (num_modifiers == 0 ||
946          (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
947         num_modifiers = 0;
948         modifiers = NULL;
949      }
950
951      flags = use_flags;
952      if (tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT)
953         flags |= __DRI_IMAGE_USE_SCANOUT;
954
955      dri2_surf->back->dri_image =
956         loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
957                                 dri2_surf->base.Width,
958                                 dri2_surf->base.Height,
959                                 dri_image_format,
960                                 dri2_dpy->is_different_gpu ? 0 : flags,
961                                 modifiers, num_modifiers, NULL);
962
963      if (dri2_surf->back->dri_image)
964         return;
965   }
966}
967
968static void
969create_dri_image(struct dri2_egl_surface *dri2_surf,
970                 unsigned int dri_image_format, uint32_t use_flags)
971{
972   struct dri2_egl_display *dri2_dpy =
973      dri2_egl_display(dri2_surf->base.Resource.Display);
974   int visual_idx;
975   uint64_t *modifiers;
976   unsigned int num_modifiers;
977
978   visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
979   modifiers = u_vector_tail(&dri2_dpy->formats.modifiers[visual_idx]);
980   num_modifiers = u_vector_length(&dri2_dpy->formats.modifiers[visual_idx]);
981
982   /* For the purposes of this function, an INVALID modifier on
983    * its own means the modifiers aren't supported. */
984   if (num_modifiers == 0 ||
985       (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
986      num_modifiers = 0;
987      modifiers = NULL;
988   }
989
990   /* If our DRIImage implementation does not support createImageWithModifiers,
991    * then fall back to the old createImage, and hope it allocates an image
992    * which is acceptable to the winsys. */
993   dri2_surf->back->dri_image =
994      loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
995                              dri2_surf->base.Width,
996                              dri2_surf->base.Height,
997                              dri_image_format,
998                              dri2_dpy->is_different_gpu ? 0 : use_flags,
999                              modifiers, num_modifiers, NULL);
1000}
1001
1002static int
1003get_back_bo(struct dri2_egl_surface *dri2_surf)
1004{
1005   struct dri2_egl_display *dri2_dpy =
1006      dri2_egl_display(dri2_surf->base.Resource.Display);
1007   int use_flags;
1008   int visual_idx;
1009   unsigned int dri_image_format;
1010   unsigned int linear_dri_image_format;
1011
1012   visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
1013   assert(visual_idx != -1);
1014   dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format;
1015   linear_dri_image_format = dri_image_format;
1016
1017   /* Substitute dri image format if server does not support original format */
1018   if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, visual_idx))
1019      linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format;
1020
1021   /* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and
1022    * the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free
1023    * of bugs.
1024    */
1025   assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE);
1026   assert(BITSET_TEST(dri2_dpy->formats.formats_bitmap,
1027          dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format)));
1028
1029   /* There might be a buffer release already queued that wasn't processed */
1030   wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
1031
1032   while (dri2_surf->back == NULL) {
1033      for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1034         /* Get an unlocked buffer, preferably one with a dri_buffer
1035          * already allocated. */
1036         if (dri2_surf->color_buffers[i].locked)
1037            continue;
1038         if (dri2_surf->back == NULL)
1039            dri2_surf->back = &dri2_surf->color_buffers[i];
1040         else if (dri2_surf->back->dri_image == NULL)
1041            dri2_surf->back = &dri2_surf->color_buffers[i];
1042      }
1043
1044      if (dri2_surf->back)
1045         break;
1046
1047      /* If we don't have a buffer, then block on the server to release one for
1048       * us, and try again. wl_display_dispatch_queue will process any pending
1049       * events, however not all servers flush on issuing a buffer release
1050       * event. So, we spam the server with roundtrips as they always cause a
1051       * client flush.
1052       */
1053      if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,
1054                                     dri2_surf->wl_queue) < 0)
1055          return -1;
1056   }
1057
1058   if (dri2_surf->back == NULL)
1059      return -1;
1060
1061   use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
1062
1063   if (dri2_surf->base.ProtectedContent) {
1064      /* Protected buffers can't be read from another GPU */
1065      if (dri2_dpy->is_different_gpu)
1066         return -1;
1067      use_flags |= __DRI_IMAGE_USE_PROTECTED;
1068   }
1069
1070   if (dri2_dpy->is_different_gpu && dri2_surf->back->linear_copy == NULL) {
1071      create_dri_image_diff_gpu(dri2_surf, linear_dri_image_format, use_flags);
1072      if (dri2_surf->back->linear_copy == NULL)
1073          return -1;
1074   }
1075
1076   if (dri2_surf->back->dri_image == NULL) {
1077      if (dri2_surf->wl_dmabuf_feedback)
1078         create_dri_image_from_dmabuf_feedback(dri2_surf, dri_image_format, use_flags);
1079      if (dri2_surf->back->dri_image == NULL)
1080         create_dri_image(dri2_surf, dri_image_format, use_flags);
1081      dri2_surf->back->age = 0;
1082   }
1083
1084   if (dri2_surf->back->dri_image == NULL)
1085      return -1;
1086
1087   dri2_surf->back->locked = true;
1088
1089   return 0;
1090}
1091
1092
1093static void
1094back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
1095{
1096   struct dri2_egl_display *dri2_dpy =
1097      dri2_egl_display(dri2_surf->base.Resource.Display);
1098   __DRIimage *image;
1099   int name, pitch;
1100
1101   image = dri2_surf->back->dri_image;
1102
1103   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
1104   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
1105
1106   buffer->attachment = __DRI_BUFFER_BACK_LEFT;
1107   buffer->name = name;
1108   buffer->pitch = pitch;
1109   buffer->cpp = 4;
1110   buffer->flags = 0;
1111}
1112
1113/* Value chosen empirically as a compromise between avoiding frequent
1114 * reallocations and extended time of increased memory consumption due to
1115 * unused buffers being kept.
1116 */
1117#define BUFFER_TRIM_AGE_HYSTERESIS 20
1118
1119static int
1120update_buffers(struct dri2_egl_surface *dri2_surf)
1121{
1122   struct dri2_egl_display *dri2_dpy =
1123      dri2_egl_display(dri2_surf->base.Resource.Display);
1124
1125   if (dri2_surf->wl_win &&
1126       (dri2_surf->base.Width != dri2_surf->wl_win->width ||
1127        dri2_surf->base.Height != dri2_surf->wl_win->height)) {
1128
1129      dri2_surf->base.Width  = dri2_surf->wl_win->width;
1130      dri2_surf->base.Height = dri2_surf->wl_win->height;
1131      dri2_surf->dx = dri2_surf->wl_win->dx;
1132      dri2_surf->dy = dri2_surf->wl_win->dy;
1133   }
1134
1135   if (dri2_surf->resized || dri2_surf->received_dmabuf_feedback) {
1136      dri2_wl_release_buffers(dri2_surf);
1137      dri2_surf->resized = false;
1138      dri2_surf->received_dmabuf_feedback = false;
1139   }
1140
1141   if (get_back_bo(dri2_surf) < 0) {
1142      _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
1143      return -1;
1144   }
1145
1146   /* If we have an extra unlocked buffer at this point, we had to do triple
1147    * buffering for a while, but now can go back to just double buffering.
1148    * That means we can free any unlocked buffer now. To avoid toggling between
1149    * going back to double buffering and needing to allocate another buffer too
1150    * fast we let the unneeded buffer sit around for a short while. */
1151   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1152      if (!dri2_surf->color_buffers[i].locked &&
1153          dri2_surf->color_buffers[i].wl_buffer &&
1154          dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) {
1155         wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
1156         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
1157         if (dri2_dpy->is_different_gpu)
1158            dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
1159         dri2_surf->color_buffers[i].wl_buffer = NULL;
1160         dri2_surf->color_buffers[i].dri_image = NULL;
1161         dri2_surf->color_buffers[i].linear_copy = NULL;
1162         dri2_surf->color_buffers[i].age = 0;
1163      }
1164   }
1165
1166   return 0;
1167}
1168
1169static int
1170update_buffers_if_needed(struct dri2_egl_surface *dri2_surf)
1171{
1172   if (dri2_surf->back != NULL)
1173      return 0;
1174
1175   return update_buffers(dri2_surf);
1176}
1177
1178static __DRIbuffer *
1179dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
1180                                int *width, int *height,
1181                                unsigned int *attachments, int count,
1182                                int *out_count, void *loaderPrivate)
1183{
1184   struct dri2_egl_surface *dri2_surf = loaderPrivate;
1185   int i, j;
1186
1187   if (update_buffers_if_needed(dri2_surf) < 0)
1188      return NULL;
1189
1190   for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
1191      __DRIbuffer *local;
1192
1193      switch (attachments[i]) {
1194      case __DRI_BUFFER_BACK_LEFT:
1195         back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
1196         break;
1197      default:
1198         local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
1199                                                     attachments[i + 1]);
1200
1201         if (!local) {
1202            _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
1203            return NULL;
1204         }
1205         dri2_surf->buffers[j] = *local;
1206         break;
1207      }
1208   }
1209
1210   *out_count = j;
1211   if (j == 0)
1212      return NULL;
1213
1214   *width = dri2_surf->base.Width;
1215   *height = dri2_surf->base.Height;
1216
1217   return dri2_surf->buffers;
1218}
1219
1220static __DRIbuffer *
1221dri2_wl_get_buffers(__DRIdrawable * driDrawable,
1222                    int *width, int *height,
1223                    unsigned int *attachments, int count,
1224                    int *out_count, void *loaderPrivate)
1225{
1226   struct dri2_egl_surface *dri2_surf = loaderPrivate;
1227   unsigned int *attachments_with_format;
1228   __DRIbuffer *buffer;
1229   int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
1230
1231   if (visual_idx == -1)
1232      return NULL;
1233
1234   attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
1235   if (!attachments_with_format) {
1236      *out_count = 0;
1237      return NULL;
1238   }
1239
1240   for (int i = 0; i < count; ++i) {
1241      attachments_with_format[2*i] = attachments[i];
1242      attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].bpp;
1243   }
1244
1245   buffer =
1246      dri2_wl_get_buffers_with_format(driDrawable,
1247                                      width, height,
1248                                      attachments_with_format, count,
1249                                      out_count, loaderPrivate);
1250
1251   free(attachments_with_format);
1252
1253   return buffer;
1254}
1255
1256static int
1257image_get_buffers(__DRIdrawable *driDrawable,
1258                  unsigned int format,
1259                  uint32_t *stamp,
1260                  void *loaderPrivate,
1261                  uint32_t buffer_mask,
1262                  struct __DRIimageList *buffers)
1263{
1264   struct dri2_egl_surface *dri2_surf = loaderPrivate;
1265
1266   if (update_buffers_if_needed(dri2_surf) < 0)
1267      return 0;
1268
1269   buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
1270   buffers->back = dri2_surf->back->dri_image;
1271
1272   return 1;
1273}
1274
1275static void
1276dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
1277{
1278   (void) driDrawable;
1279   (void) loaderPrivate;
1280}
1281
1282static unsigned
1283dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
1284{
1285   switch (cap) {
1286   case DRI_LOADER_CAP_FP16:
1287      return 1;
1288   case DRI_LOADER_CAP_RGBA_ORDERING:
1289      return 1;
1290   default:
1291      return 0;
1292   }
1293}
1294
1295static const __DRIdri2LoaderExtension dri2_loader_extension = {
1296   .base = { __DRI_DRI2_LOADER, 4 },
1297
1298   .getBuffers           = dri2_wl_get_buffers,
1299   .flushFrontBuffer     = dri2_wl_flush_front_buffer,
1300   .getBuffersWithFormat = dri2_wl_get_buffers_with_format,
1301   .getCapability        = dri2_wl_get_capability,
1302};
1303
1304static const __DRIimageLoaderExtension image_loader_extension = {
1305   .base = { __DRI_IMAGE_LOADER, 2 },
1306
1307   .getBuffers          = image_get_buffers,
1308   .flushFrontBuffer    = dri2_wl_flush_front_buffer,
1309   .getCapability       = dri2_wl_get_capability,
1310};
1311
1312static void
1313wayland_throttle_callback(void *data,
1314                          struct wl_callback *callback,
1315                          uint32_t time)
1316{
1317   struct dri2_egl_surface *dri2_surf = data;
1318
1319   dri2_surf->throttle_callback = NULL;
1320   wl_callback_destroy(callback);
1321}
1322
1323static const struct wl_callback_listener throttle_listener = {
1324   .done = wayland_throttle_callback
1325};
1326
1327static EGLBoolean
1328get_fourcc(struct dri2_egl_display *dri2_dpy,
1329           __DRIimage *image, int *fourcc)
1330{
1331   EGLBoolean query;
1332   int dri_format;
1333   int visual_idx;
1334
1335   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,
1336                                       fourcc);
1337   if (query)
1338      return true;
1339
1340   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,
1341                                       &dri_format);
1342   if (!query)
1343      return false;
1344
1345   visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format);
1346   if (visual_idx == -1)
1347      return false;
1348
1349   *fourcc = dri2_wl_visuals[visual_idx].wl_drm_format;
1350   return true;
1351}
1352
1353static struct wl_buffer *
1354create_wl_buffer(struct dri2_egl_display *dri2_dpy,
1355                 struct dri2_egl_surface *dri2_surf,
1356                 __DRIimage *image)
1357{
1358   struct wl_buffer *ret = NULL;
1359   EGLBoolean query;
1360   int width, height, fourcc, num_planes;
1361   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
1362
1363   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
1364   query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,
1365                                        &height);
1366   query &= get_fourcc(dri2_dpy, image, &fourcc);
1367   if (!query)
1368      return NULL;
1369
1370   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
1371                                       &num_planes);
1372   if (!query)
1373      num_planes = 1;
1374
1375   if (dri2_dpy->image->base.version >= 15) {
1376      int mod_hi, mod_lo;
1377
1378      query = dri2_dpy->image->queryImage(image,
1379                                          __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
1380                                          &mod_hi);
1381      query &= dri2_dpy->image->queryImage(image,
1382                                           __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
1383                                           &mod_lo);
1384      if (query) {
1385         modifier = combine_u32_into_u64(mod_hi, mod_lo);
1386      }
1387   }
1388
1389   bool supported_modifier = false;
1390   bool mod_invalid_supported = false;
1391   int visual_idx = dri2_wl_visual_idx_from_fourcc(fourcc);
1392   assert(visual_idx != -1);
1393
1394   uint64_t *mod;
1395   u_vector_foreach(mod, &dri2_dpy->formats.modifiers[visual_idx]) {
1396      if (*mod == DRM_FORMAT_MOD_INVALID) {
1397         mod_invalid_supported = true;
1398      }
1399      if (*mod == modifier) {
1400         supported_modifier = true;
1401         break;
1402      }
1403   }
1404   if (!supported_modifier && mod_invalid_supported) {
1405      /* If the server has advertised DRM_FORMAT_MOD_INVALID then we trust
1406       * that the client has allocated the buffer with the right implicit
1407       * modifier for the format, even though it's allocated a buffer the
1408       * server hasn't explicitly claimed to support. */
1409      modifier = DRM_FORMAT_MOD_INVALID;
1410      supported_modifier = true;
1411   }
1412
1413   if (dri2_dpy->wl_dmabuf && supported_modifier) {
1414      struct zwp_linux_buffer_params_v1 *params;
1415      int i;
1416
1417      /* We don't need a wrapper for wl_dmabuf objects, because we have to
1418       * create the intermediate params object; we can set the queue on this,
1419       * and the wl_buffer inherits it race-free. */
1420      params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
1421      if (dri2_surf)
1422         wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);
1423
1424      for (i = 0; i < num_planes; i++) {
1425         __DRIimage *p_image;
1426         int stride, offset;
1427         int fd = -1;
1428
1429         p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
1430         if (!p_image) {
1431            assert(i == 0);
1432            p_image = image;
1433         }
1434
1435         query = dri2_dpy->image->queryImage(p_image,
1436                                             __DRI_IMAGE_ATTRIB_FD,
1437                                             &fd);
1438         query &= dri2_dpy->image->queryImage(p_image,
1439                                              __DRI_IMAGE_ATTRIB_STRIDE,
1440                                              &stride);
1441         query &= dri2_dpy->image->queryImage(p_image,
1442                                              __DRI_IMAGE_ATTRIB_OFFSET,
1443                                              &offset);
1444         if (image != p_image)
1445            dri2_dpy->image->destroyImage(p_image);
1446
1447         if (!query) {
1448            if (fd >= 0)
1449               close(fd);
1450            zwp_linux_buffer_params_v1_destroy(params);
1451            return NULL;
1452         }
1453
1454         zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
1455                                        modifier >> 32, modifier & 0xffffffff);
1456         close(fd);
1457      }
1458
1459      ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
1460                                                    fourcc, 0);
1461      zwp_linux_buffer_params_v1_destroy(params);
1462   } else {
1463      struct wl_drm *wl_drm =
1464         dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
1465      int fd = -1, stride;
1466
1467      if (num_planes > 1)
1468         return NULL;
1469
1470      query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
1471      query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
1472      if (!query) {
1473         if (fd >= 0)
1474            close(fd);
1475         return NULL;
1476      }
1477
1478      ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
1479                                       stride, 0, 0, 0, 0);
1480      close(fd);
1481   }
1482
1483   return ret;
1484}
1485
1486static EGLBoolean
1487try_damage_buffer(struct dri2_egl_surface *dri2_surf,
1488                  const EGLint *rects,
1489                  EGLint n_rects)
1490{
1491   if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)
1492       < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
1493      return EGL_FALSE;
1494
1495   for (int i = 0; i < n_rects; i++) {
1496      const int *rect = &rects[i * 4];
1497
1498      wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,
1499                               rect[0],
1500                               dri2_surf->base.Height - rect[1] - rect[3],
1501                               rect[2], rect[3]);
1502   }
1503   return EGL_TRUE;
1504}
1505
1506/**
1507 * Called via eglSwapBuffers(), drv->SwapBuffers().
1508 */
1509static EGLBoolean
1510dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp,
1511                                 _EGLSurface *draw,
1512                                 const EGLint *rects,
1513                                 EGLint n_rects)
1514{
1515   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1516   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
1517
1518   if (!dri2_surf->wl_win)
1519      return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");
1520
1521   while (dri2_surf->throttle_callback != NULL)
1522      if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
1523                                    dri2_surf->wl_queue) == -1)
1524         return -1;
1525
1526   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
1527      if (dri2_surf->color_buffers[i].age > 0)
1528         dri2_surf->color_buffers[i].age++;
1529
1530   /* Make sure we have a back buffer in case we're swapping without ever
1531    * rendering. */
1532   if (update_buffers_if_needed(dri2_surf) < 0)
1533      return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
1534
1535   if (draw->SwapInterval > 0) {
1536      dri2_surf->throttle_callback =
1537         wl_surface_frame(dri2_surf->wl_surface_wrapper);
1538      wl_callback_add_listener(dri2_surf->throttle_callback,
1539                               &throttle_listener, dri2_surf);
1540   }
1541
1542   dri2_surf->back->age = 1;
1543   dri2_surf->current = dri2_surf->back;
1544   dri2_surf->back = NULL;
1545
1546   if (!dri2_surf->current->wl_buffer) {
1547      __DRIimage *image;
1548
1549      if (dri2_dpy->is_different_gpu)
1550         image = dri2_surf->current->linear_copy;
1551      else
1552         image = dri2_surf->current->dri_image;
1553
1554      dri2_surf->current->wl_buffer =
1555         create_wl_buffer(dri2_dpy, dri2_surf, image);
1556
1557      dri2_surf->current->wl_release = false;
1558
1559      wl_buffer_add_listener(dri2_surf->current->wl_buffer,
1560                             &wl_buffer_listener, dri2_surf);
1561   }
1562
1563   wl_surface_attach(dri2_surf->wl_surface_wrapper,
1564                     dri2_surf->current->wl_buffer,
1565                     dri2_surf->dx, dri2_surf->dy);
1566
1567   dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
1568   dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
1569   /* reset resize growing parameters */
1570   dri2_surf->dx = 0;
1571   dri2_surf->dy = 0;
1572
1573   /* If the compositor doesn't support damage_buffer, we deliberately
1574    * ignore the damage region and post maximum damage, due to
1575    * https://bugs.freedesktop.org/78190 */
1576   if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
1577      wl_surface_damage(dri2_surf->wl_surface_wrapper,
1578                        0, 0, INT32_MAX, INT32_MAX);
1579
1580   if (dri2_dpy->is_different_gpu) {
1581      _EGLContext *ctx = _eglGetCurrentContext();
1582      struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1583      dri2_dpy->image->blitImage(dri2_ctx->dri_context,
1584                                 dri2_surf->current->linear_copy,
1585                                 dri2_surf->current->dri_image,
1586                                 0, 0, dri2_surf->base.Width,
1587                                 dri2_surf->base.Height,
1588                                 0, 0, dri2_surf->base.Width,
1589                                 dri2_surf->base.Height, 0);
1590   }
1591
1592   dri2_flush_drawable_for_swapbuffers(disp, draw);
1593   dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
1594
1595   wl_surface_commit(dri2_surf->wl_surface_wrapper);
1596
1597   /* If we're not waiting for a frame callback then we'll at least throttle
1598    * to a sync callback so that we always give a chance for the compositor to
1599    * handle the commit and send a release event before checking for a free
1600    * buffer */
1601   if (dri2_surf->throttle_callback == NULL) {
1602      dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
1603      wl_callback_add_listener(dri2_surf->throttle_callback,
1604                               &throttle_listener, dri2_surf);
1605   }
1606
1607   wl_display_flush(dri2_dpy->wl_dpy);
1608
1609   return EGL_TRUE;
1610}
1611
1612static EGLint
1613dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
1614{
1615   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
1616
1617   if (update_buffers_if_needed(dri2_surf) < 0) {
1618      _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
1619      return -1;
1620   }
1621
1622   return dri2_surf->back->age;
1623}
1624
1625static EGLBoolean
1626dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
1627{
1628   return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0);
1629}
1630
1631static struct wl_buffer *
1632dri2_wl_create_wayland_buffer_from_image(_EGLDisplay *disp, _EGLImage *img)
1633{
1634   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1635   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
1636   __DRIimage *image = dri2_img->dri_image;
1637   struct wl_buffer *buffer;
1638   int format, visual_idx;
1639
1640   /* Check the upstream display supports this buffer's format. */
1641   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
1642   visual_idx = dri2_wl_visual_idx_from_dri_image_format(format);
1643   if (visual_idx == -1)
1644      goto bad_format;
1645
1646   if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, visual_idx))
1647      goto bad_format;
1648
1649   buffer = create_wl_buffer(dri2_dpy, NULL, image);
1650
1651   /* The buffer object will have been created with our internal event queue
1652    * because it is using wl_dmabuf/wl_drm as a proxy factory. We want the
1653    * buffer to be used by the application so we'll reset it to the display's
1654    * default event queue. This isn't actually racy, as the only event the
1655    * buffer can get is a buffer release, which doesn't happen with an explicit
1656    * attach. */
1657   if (buffer)
1658      wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
1659
1660   return buffer;
1661
1662bad_format:
1663   _eglError(EGL_BAD_MATCH, "unsupported image format");
1664   return NULL;
1665}
1666
1667static int
1668dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
1669{
1670   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1671   int ret = 0;
1672
1673   if (dri2_dpy->is_render_node) {
1674      _eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
1675                            "authenticate for render-nodes");
1676      return 0;
1677   }
1678   dri2_dpy->authenticated = false;
1679
1680   wl_drm_authenticate(dri2_dpy->wl_drm, id);
1681   if (roundtrip(dri2_dpy) < 0)
1682      ret = -1;
1683
1684   if (!dri2_dpy->authenticated)
1685      ret = -1;
1686
1687   /* reset authenticated */
1688   dri2_dpy->authenticated = true;
1689
1690   return ret;
1691}
1692
1693static void
1694drm_handle_device(void *data, struct wl_drm *drm, const char *device)
1695{
1696   struct dri2_egl_display *dri2_dpy = data;
1697   drm_magic_t magic;
1698
1699   dri2_dpy->device_name = strdup(device);
1700   if (!dri2_dpy->device_name)
1701      return;
1702
1703   dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
1704   if (dri2_dpy->fd == -1) {
1705      _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
1706              dri2_dpy->device_name, strerror(errno));
1707      free(dri2_dpy->device_name);
1708      dri2_dpy->device_name = NULL;
1709      return;
1710   }
1711
1712   if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
1713      dri2_dpy->authenticated = true;
1714   } else {
1715      if (drmGetMagic(dri2_dpy->fd, &magic)) {
1716         close(dri2_dpy->fd);
1717         dri2_dpy->fd = -1;
1718         free(dri2_dpy->device_name);
1719         dri2_dpy->device_name = NULL;
1720         _eglLog(_EGL_WARNING, "wayland-egl: drmGetMagic failed");
1721         return;
1722      }
1723      wl_drm_authenticate(dri2_dpy->wl_drm, magic);
1724   }
1725}
1726
1727static void
1728drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
1729{
1730   struct dri2_egl_display *dri2_dpy = data;
1731   int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
1732
1733   if (visual_idx == -1)
1734      return;
1735
1736   BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx);
1737}
1738
1739static void
1740drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
1741{
1742   struct dri2_egl_display *dri2_dpy = data;
1743
1744   dri2_dpy->capabilities = value;
1745}
1746
1747static void
1748drm_handle_authenticated(void *data, struct wl_drm *drm)
1749{
1750   struct dri2_egl_display *dri2_dpy = data;
1751
1752   dri2_dpy->authenticated = true;
1753}
1754
1755static const struct wl_drm_listener drm_listener = {
1756   .device = drm_handle_device,
1757   .format = drm_handle_format,
1758   .authenticated = drm_handle_authenticated,
1759   .capabilities = drm_handle_capabilities
1760};
1761
1762static void
1763dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
1764                     uint32_t format)
1765{
1766   /* formats are implicitly advertised by the 'modifier' event, so ignore */
1767}
1768
1769static void
1770dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
1771                       uint32_t format, uint32_t modifier_hi,
1772                       uint32_t modifier_lo)
1773{
1774   struct dri2_egl_display *dri2_dpy = data;
1775   int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
1776   uint64_t *mod;
1777
1778   /* Ignore this if the compositor advertised dma-buf feedback. From version 4
1779    * onwards (when dma-buf feedback was introduced), the compositor should not
1780    * advertise this event anymore, but let's keep this for safety. */
1781   if (dri2_dpy->wl_dmabuf_feedback)
1782      return;
1783
1784   if (visual_idx == -1)
1785      return;
1786
1787   BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx);
1788
1789   mod = u_vector_add(&dri2_dpy->formats.modifiers[visual_idx]);
1790   if (mod)
1791      *mod = combine_u32_into_u64(modifier_hi, modifier_lo);
1792}
1793
1794static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
1795   .format = dmabuf_ignore_format,
1796   .modifier = dmabuf_handle_modifier,
1797};
1798
1799static void
1800wl_drm_bind(struct dri2_egl_display *dri2_dpy)
1801{
1802   dri2_dpy->wl_drm = wl_registry_bind(dri2_dpy->wl_registry, dri2_dpy->wl_drm_name,
1803                                       &wl_drm_interface, dri2_dpy->wl_drm_version);
1804   wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
1805}
1806
1807static void
1808default_dmabuf_feedback_format_table(void *data,
1809                                     struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
1810                                     int32_t fd, uint32_t size)
1811{
1812   struct dri2_egl_display *dri2_dpy = data;
1813
1814   dri2_dpy->format_table.size = size;
1815   dri2_dpy->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
1816
1817   close(fd);
1818}
1819
1820static void
1821default_dmabuf_feedback_main_device(void *data,
1822                                    struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
1823                                    struct wl_array *device)
1824{
1825   struct dri2_egl_display *dri2_dpy = data;
1826   char *node;
1827   int fd;
1828   dev_t dev;
1829
1830   /* Given the device, look for a render node and try to open it. */
1831   memcpy(&dev, device->data, sizeof(dev));
1832   node = loader_get_render_node(dev);
1833   if (!node)
1834      return;
1835   fd = loader_open_device(node);
1836   if (fd == -1) {
1837      free(node);
1838      return;
1839   }
1840
1841   dri2_dpy->device_name = node;
1842   dri2_dpy->fd = fd;
1843   dri2_dpy->authenticated = true;
1844}
1845
1846static void
1847default_dmabuf_feedback_tranche_target_device(void *data,
1848                                              struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
1849                                              struct wl_array *device)
1850{
1851   /* ignore this event */
1852}
1853
1854static void
1855default_dmabuf_feedback_tranche_flags(void *data,
1856                                      struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
1857                                      uint32_t flags)
1858{
1859   /* ignore this event */
1860}
1861
1862static void
1863default_dmabuf_feedback_tranche_formats(void *data,
1864                                        struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
1865                                        struct wl_array *indices)
1866{
1867   struct dri2_egl_display *dri2_dpy = data;
1868   uint64_t *modifier_ptr, modifier;
1869   uint32_t format;
1870   uint16_t *index;
1871   int visual_idx;
1872
1873   if (dri2_dpy->format_table.data == MAP_FAILED) {
1874      _eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table "
1875                            "so we won't be able to use this batch of dma-buf "
1876                            "feedback events.");
1877      return;
1878   }
1879   if (dri2_dpy->format_table.data == NULL) {
1880      _eglLog(_EGL_WARNING, "wayland-egl: compositor didn't advertise a format "
1881                            "table, so we won't be able to use this batch of dma-buf "
1882                            "feedback events.");
1883      return;
1884   }
1885
1886   wl_array_for_each(index, indices) {
1887      format = dri2_dpy->format_table.data[*index].format;
1888      modifier = dri2_dpy->format_table.data[*index].modifier;
1889
1890      /* skip formats that we don't support */
1891      visual_idx = dri2_wl_visual_idx_from_fourcc(format);
1892      if (visual_idx == -1)
1893         continue;
1894
1895      BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx);
1896      modifier_ptr = u_vector_add(&dri2_dpy->formats.modifiers[visual_idx]);
1897      if (modifier_ptr)
1898         *modifier_ptr = modifier;
1899   }
1900}
1901
1902static void
1903default_dmabuf_feedback_tranche_done(void *data,
1904                                     struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
1905{
1906   /* ignore this event */
1907}
1908
1909static void
1910default_dmabuf_feedback_done(void *data,
1911                             struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
1912{
1913   /* ignore this event */
1914}
1915
1916static const struct zwp_linux_dmabuf_feedback_v1_listener
1917dmabuf_feedback_listener = {
1918   .format_table = default_dmabuf_feedback_format_table,
1919   .main_device = default_dmabuf_feedback_main_device,
1920   .tranche_target_device = default_dmabuf_feedback_tranche_target_device,
1921   .tranche_flags = default_dmabuf_feedback_tranche_flags,
1922   .tranche_formats = default_dmabuf_feedback_tranche_formats,
1923   .tranche_done = default_dmabuf_feedback_tranche_done,
1924   .done = default_dmabuf_feedback_done,
1925};
1926
1927static void
1928registry_handle_global_drm(void *data, struct wl_registry *registry,
1929                           uint32_t name, const char *interface,
1930                           uint32_t version)
1931{
1932   struct dri2_egl_display *dri2_dpy = data;
1933
1934   if (strcmp(interface, "wl_drm") == 0) {
1935      dri2_dpy->wl_drm_version = MIN2(version, 2);
1936      dri2_dpy->wl_drm_name = name;
1937   } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
1938      dri2_dpy->wl_dmabuf =
1939         wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
1940                          MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION));
1941      zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
1942                                       dri2_dpy);
1943   }
1944}
1945
1946static void
1947registry_handle_global_remove(void *data, struct wl_registry *registry,
1948                              uint32_t name)
1949{
1950}
1951
1952static const struct wl_registry_listener registry_listener_drm = {
1953   .global = registry_handle_global_drm,
1954   .global_remove = registry_handle_global_remove
1955};
1956
1957static void
1958dri2_wl_setup_swap_interval(_EGLDisplay *disp)
1959{
1960   /* We can't use values greater than 1 on Wayland because we are using the
1961    * frame callback to synchronise the frame and the only way we be sure to
1962    * get a frame callback is to attach a new buffer. Therefore we can't just
1963    * sit drawing nothing to wait until the next ‘n’ frame callbacks */
1964
1965   dri2_setup_swap_interval(disp, 1);
1966}
1967
1968static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
1969   .authenticate = dri2_wl_authenticate,
1970   .create_window_surface = dri2_wl_create_window_surface,
1971   .create_pixmap_surface = dri2_wl_create_pixmap_surface,
1972   .destroy_surface = dri2_wl_destroy_surface,
1973   .swap_interval = dri2_wl_swap_interval,
1974   .create_image = dri2_create_image_khr,
1975   .swap_buffers = dri2_wl_swap_buffers,
1976   .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
1977   .query_buffer_age = dri2_wl_query_buffer_age,
1978   .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
1979   .get_dri_drawable = dri2_surface_get_dri_drawable,
1980};
1981
1982static const __DRIextension *dri2_loader_extensions[] = {
1983   &dri2_loader_extension.base,
1984   &image_loader_extension.base,
1985   &image_lookup_extension.base,
1986   &use_invalidate.base,
1987   NULL,
1988};
1989
1990static const __DRIextension *image_loader_extensions[] = {
1991   &image_loader_extension.base,
1992   &image_lookup_extension.base,
1993   &use_invalidate.base,
1994   NULL,
1995};
1996
1997static EGLBoolean
1998dri2_wl_add_configs_for_visuals(_EGLDisplay *disp)
1999{
2000   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2001   unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 };
2002   unsigned int count = 0;
2003   bool assigned;
2004
2005   for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
2006      assigned = false;
2007
2008      for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) {
2009         struct dri2_egl_config *dri2_conf;
2010
2011         if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, j))
2012            continue;
2013
2014         dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
2015               count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes);
2016         if (dri2_conf) {
2017            if (dri2_conf->base.ConfigID == count + 1)
2018               count++;
2019            format_count[j]++;
2020            assigned = true;
2021         }
2022      }
2023
2024      if (!assigned && dri2_dpy->is_different_gpu) {
2025         struct dri2_egl_config *dri2_conf;
2026         int alt_dri_image_format, c, s;
2027
2028         /* No match for config. Try if we can blitImage convert to a visual */
2029         c = dri2_wl_visual_idx_from_config(dri2_dpy,
2030                                            dri2_dpy->driver_configs[i],
2031                                            false);
2032
2033         if (c == -1)
2034            continue;
2035
2036         /* Find optimal target visual for blitImage conversion, if any. */
2037         alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format;
2038         s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format);
2039
2040         if (s == -1 || !BITSET_TEST(dri2_dpy->formats.formats_bitmap, s))
2041            continue;
2042
2043         /* Visual s works for the Wayland server, and c can be converted into s
2044          * by our client gpu during PRIME blitImage conversion to a linear
2045          * wl_buffer, so add visual c as supported by the client renderer.
2046          */
2047         dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
2048                                     count + 1, EGL_WINDOW_BIT, NULL,
2049                                     dri2_wl_visuals[c].rgba_shifts,
2050                                     dri2_wl_visuals[c].rgba_sizes);
2051         if (dri2_conf) {
2052            if (dri2_conf->base.ConfigID == count + 1)
2053               count++;
2054            format_count[c]++;
2055            if (format_count[c] == 1)
2056               _eglLog(_EGL_DEBUG, "Client format %s to server format %s via "
2057                       "PRIME blitImage.", dri2_wl_visuals[c].format_name,
2058                       dri2_wl_visuals[s].format_name);
2059         }
2060      }
2061   }
2062
2063   for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
2064      if (!format_count[i]) {
2065         _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
2066                 dri2_wl_visuals[i].format_name);
2067      }
2068   }
2069
2070   return (count != 0);
2071}
2072
2073static EGLBoolean
2074dri2_initialize_wayland_drm(_EGLDisplay *disp)
2075{
2076   _EGLDevice *dev;
2077   struct dri2_egl_display *dri2_dpy;
2078
2079   dri2_dpy = calloc(1, sizeof *dri2_dpy);
2080   if (!dri2_dpy)
2081      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
2082
2083   dri2_dpy->fd = -1;
2084   disp->DriverData = (void *) dri2_dpy;
2085
2086   if (dri2_wl_formats_init(&dri2_dpy->formats) < 0)
2087      goto cleanup;
2088
2089   if (disp->PlatformDisplay == NULL) {
2090      dri2_dpy->wl_dpy = wl_display_connect(NULL);
2091      if (dri2_dpy->wl_dpy == NULL)
2092         goto cleanup;
2093      dri2_dpy->own_device = true;
2094   } else {
2095      dri2_dpy->wl_dpy = disp->PlatformDisplay;
2096   }
2097
2098   dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
2099
2100   dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
2101   if (dri2_dpy->wl_dpy_wrapper == NULL)
2102      goto cleanup;
2103
2104   wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
2105                      dri2_dpy->wl_queue);
2106
2107   if (dri2_dpy->own_device)
2108      wl_display_dispatch_pending(dri2_dpy->wl_dpy);
2109
2110   dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
2111   wl_registry_add_listener(dri2_dpy->wl_registry,
2112                            &registry_listener_drm, dri2_dpy);
2113
2114   if (roundtrip(dri2_dpy) < 0)
2115      goto cleanup;
2116
2117   /* Get default dma-buf feedback */
2118   if (dri2_dpy->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >=
2119                              ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) {
2120      dmabuf_feedback_format_table_init(&dri2_dpy->format_table);
2121      dri2_dpy->wl_dmabuf_feedback =
2122         zwp_linux_dmabuf_v1_get_default_feedback(dri2_dpy->wl_dmabuf);
2123      zwp_linux_dmabuf_feedback_v1_add_listener(dri2_dpy->wl_dmabuf_feedback,
2124                                                &dmabuf_feedback_listener, dri2_dpy);
2125   }
2126
2127   if (roundtrip(dri2_dpy) < 0)
2128      goto cleanup;
2129
2130   /* Destroy the default dma-buf feedback and the format table. */
2131   if (dri2_dpy->wl_dmabuf_feedback) {
2132      zwp_linux_dmabuf_feedback_v1_destroy(dri2_dpy->wl_dmabuf_feedback);
2133      dri2_dpy->wl_dmabuf_feedback = NULL;
2134      dmabuf_feedback_format_table_fini(&dri2_dpy->format_table);
2135   }
2136
2137   /* We couldn't retrieve a render node from the dma-buf feedback (or the
2138    * feedback was not advertised at all), so we must fallback to wl_drm. */
2139   if (dri2_dpy->fd == -1) {
2140      /* wl_drm not advertised by compositor, so can't continue */
2141      if (dri2_dpy->wl_drm_name == 0)
2142         goto cleanup;
2143      wl_drm_bind(dri2_dpy);
2144
2145      if (dri2_dpy->wl_drm == NULL)
2146         goto cleanup;
2147      if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
2148         goto cleanup;
2149
2150      if (!dri2_dpy->authenticated &&
2151          (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))
2152         goto cleanup;
2153   }
2154
2155   dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
2156                                               &dri2_dpy->is_different_gpu);
2157   dev = _eglAddDevice(dri2_dpy->fd, false);
2158   if (!dev) {
2159      _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
2160      goto cleanup;
2161   }
2162
2163   disp->Device = dev;
2164
2165   if (dri2_dpy->is_different_gpu) {
2166      free(dri2_dpy->device_name);
2167      dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
2168      if (!dri2_dpy->device_name) {
2169         _eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
2170                                  "for requested GPU");
2171         goto cleanup;
2172      }
2173   }
2174
2175   /* we have to do the check now, because loader_get_user_preferred_fd
2176    * will return a render-node when the requested gpu is different
2177    * to the server, but also if the client asks for the same gpu than
2178    * the server by requesting its pci-id */
2179   dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
2180
2181   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
2182   if (dri2_dpy->driver_name == NULL) {
2183      _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
2184      goto cleanup;
2185   }
2186
2187   /* render nodes cannot use Gem names, and thus do not support
2188    * the __DRI_DRI2_LOADER extension */
2189   if (!dri2_dpy->is_render_node) {
2190      dri2_dpy->loader_extensions = dri2_loader_extensions;
2191      if (!dri2_load_driver(disp)) {
2192         _eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver");
2193         goto cleanup;
2194      }
2195   } else {
2196      dri2_dpy->loader_extensions = image_loader_extensions;
2197      if (!dri2_load_driver_dri3(disp)) {
2198         _eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver");
2199         goto cleanup;
2200      }
2201   }
2202
2203   if (!dri2_create_screen(disp))
2204      goto cleanup;
2205
2206   if (!dri2_setup_extensions(disp))
2207      goto cleanup;
2208
2209   dri2_setup_screen(disp);
2210
2211   dri2_wl_setup_swap_interval(disp);
2212
2213   if (dri2_dpy->wl_drm) {
2214      /* To use Prime, we must have _DRI_IMAGE v7 at least. createImageFromFds
2215       * support indicates that Prime export/import is supported by the driver.
2216       * We deprecated the support to GEM names API, so we bail out if the
2217       * driver does not suport Prime. */
2218      if (!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) ||
2219          (dri2_dpy->image->base.version < 7) ||
2220          (dri2_dpy->image->createImageFromFds == NULL)) {
2221         _eglLog(_EGL_WARNING, "wayland-egl: display does not support prime");
2222         goto cleanup;
2223      }
2224   }
2225
2226   if (dri2_dpy->is_different_gpu &&
2227       (dri2_dpy->image->base.version < 9 ||
2228        dri2_dpy->image->blitImage == NULL)) {
2229      _eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "
2230                            "Image extension in the driver is not "
2231                            "compatible. Version 9 or later and blitImage() "
2232                            "are required");
2233      goto cleanup;
2234   }
2235
2236   if (!dri2_wl_add_configs_for_visuals(disp)) {
2237      _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
2238      goto cleanup;
2239   }
2240
2241   dri2_set_WL_bind_wayland_display(disp);
2242   /* When cannot convert EGLImage to wl_buffer when on a different gpu,
2243    * because the buffer of the EGLImage has likely a tiling mode the server
2244    * gpu won't support. These is no way to check for now. Thus do not support the
2245    * extension */
2246   if (!dri2_dpy->is_different_gpu)
2247      disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
2248
2249   disp->Extensions.EXT_buffer_age = EGL_TRUE;
2250
2251   disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
2252
2253   disp->Extensions.EXT_present_opaque = EGL_TRUE;
2254
2255   /* Fill vtbl last to prevent accidentally calling virtual function during
2256    * initialization.
2257    */
2258   dri2_dpy->vtbl = &dri2_wl_display_vtbl;
2259
2260   return EGL_TRUE;
2261
2262 cleanup:
2263   dri2_display_destroy(disp);
2264   return EGL_FALSE;
2265}
2266
2267static int
2268dri2_wl_swrast_get_stride_for_format(int format, int w)
2269{
2270   int visual_idx = dri2_wl_visual_idx_from_shm_format(format);
2271
2272   assume(visual_idx != -1);
2273
2274   return w * (dri2_wl_visuals[visual_idx].bpp / 8);
2275}
2276
2277static EGLBoolean
2278dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf,
2279                               int format, int w, int h,
2280                               void **data, int *size,
2281                               struct wl_buffer **buffer)
2282{
2283   struct dri2_egl_display *dri2_dpy =
2284      dri2_egl_display(dri2_surf->base.Resource.Display);
2285   struct wl_shm_pool *pool;
2286   int fd, stride, size_map;
2287   void *data_map;
2288
2289   stride = dri2_wl_swrast_get_stride_for_format(format, w);
2290   size_map = h * stride;
2291
2292   /* Create a shareable buffer */
2293   fd = os_create_anonymous_file(size_map, NULL);
2294   if (fd < 0)
2295      return EGL_FALSE;
2296
2297   data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2298   if (data_map == MAP_FAILED) {
2299      close(fd);
2300      return EGL_FALSE;
2301   }
2302
2303   /* Share it in a wl_buffer */
2304   pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
2305   wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue);
2306   *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
2307   wl_shm_pool_destroy(pool);
2308   close(fd);
2309
2310   *data = data_map;
2311   *size = size_map;
2312   return EGL_TRUE;
2313}
2314
2315static int
2316swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
2317{
2318   struct dri2_egl_display *dri2_dpy =
2319      dri2_egl_display(dri2_surf->base.Resource.Display);
2320   bool zink = dri2_surf->base.Resource.Display->Options.Zink;
2321
2322   /* we need to do the following operations only once per frame */
2323   if (dri2_surf->back)
2324      return 0;
2325
2326   if (dri2_surf->wl_win &&
2327       (dri2_surf->base.Width != dri2_surf->wl_win->width ||
2328        dri2_surf->base.Height != dri2_surf->wl_win->height)) {
2329
2330      if (!zink)
2331         dri2_wl_release_buffers(dri2_surf);
2332
2333      dri2_surf->base.Width  = dri2_surf->wl_win->width;
2334      dri2_surf->base.Height = dri2_surf->wl_win->height;
2335      dri2_surf->dx = dri2_surf->wl_win->dx;
2336      dri2_surf->dy = dri2_surf->wl_win->dy;
2337      dri2_surf->current = NULL;
2338   }
2339
2340   /* find back buffer */
2341
2342   /* There might be a buffer release already queued that wasn't processed */
2343   wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
2344
2345   /* try get free buffer already created */
2346   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
2347      if (!dri2_surf->color_buffers[i].locked &&
2348          dri2_surf->color_buffers[i].wl_buffer) {
2349          dri2_surf->back = &dri2_surf->color_buffers[i];
2350          break;
2351      }
2352   }
2353
2354   /* else choose any another free location */
2355   if (!dri2_surf->back) {
2356      for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
2357         if (!dri2_surf->color_buffers[i].locked) {
2358             dri2_surf->back = &dri2_surf->color_buffers[i];
2359             if (zink)
2360                continue;
2361             if (!dri2_wl_swrast_allocate_buffer(dri2_surf,
2362                                                 dri2_surf->format,
2363                                                 dri2_surf->base.Width,
2364                                                 dri2_surf->base.Height,
2365                                                 &dri2_surf->back->data,
2366                                                 &dri2_surf->back->data_size,
2367                                                 &dri2_surf->back->wl_buffer)) {
2368                _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
2369                 return -1;
2370             }
2371             wl_buffer_add_listener(dri2_surf->back->wl_buffer,
2372                                    &wl_buffer_listener, dri2_surf);
2373             break;
2374         }
2375      }
2376   }
2377
2378   if (!dri2_surf->back) {
2379      _eglError(EGL_BAD_ALLOC, "failed to find free buffer");
2380      return -1;
2381   }
2382
2383   dri2_surf->back->locked = true;
2384
2385   /* If we have an extra unlocked buffer at this point, we had to do triple
2386    * buffering for a while, but now can go back to just double buffering.
2387    * That means we can free any unlocked buffer now. To avoid toggling between
2388    * going back to double buffering and needing to allocate another buffer too
2389    * fast we let the unneeded buffer sit around for a short while. */
2390   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
2391      if (!dri2_surf->color_buffers[i].locked &&
2392          dri2_surf->color_buffers[i].wl_buffer &&
2393          dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) {
2394         if (!zink) {
2395            wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
2396            munmap(dri2_surf->color_buffers[i].data,
2397                   dri2_surf->color_buffers[i].data_size);
2398         }
2399         dri2_surf->color_buffers[i].wl_buffer = NULL;
2400         dri2_surf->color_buffers[i].data = NULL;
2401         dri2_surf->color_buffers[i].age = 0;
2402      }
2403   }
2404
2405   return 0;
2406}
2407
2408static void*
2409dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
2410{
2411   /* if there has been a resize: */
2412   if (!dri2_surf->current)
2413      return NULL;
2414
2415   return dri2_surf->current->data;
2416}
2417
2418static void*
2419dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
2420{
2421   assert(dri2_surf->back);
2422   return dri2_surf->back->data;
2423}
2424
2425static void
2426dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
2427{
2428   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
2429
2430   while (dri2_surf->throttle_callback != NULL)
2431      if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
2432                                    dri2_surf->wl_queue) == -1)
2433         return;
2434
2435   if (dri2_surf->base.SwapInterval > 0) {
2436      dri2_surf->throttle_callback =
2437         wl_surface_frame(dri2_surf->wl_surface_wrapper);
2438      wl_callback_add_listener(dri2_surf->throttle_callback,
2439                               &throttle_listener, dri2_surf);
2440   }
2441
2442   dri2_surf->current = dri2_surf->back;
2443   dri2_surf->back = NULL;
2444
2445   wl_surface_attach(dri2_surf->wl_surface_wrapper,
2446                     dri2_surf->current->wl_buffer,
2447                     dri2_surf->dx, dri2_surf->dy);
2448
2449   dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
2450   dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
2451   /* reset resize growing parameters */
2452   dri2_surf->dx = 0;
2453   dri2_surf->dy = 0;
2454
2455   wl_surface_damage(dri2_surf->wl_surface_wrapper,
2456                     0, 0, INT32_MAX, INT32_MAX);
2457   wl_surface_commit(dri2_surf->wl_surface_wrapper);
2458
2459   /* If we're not waiting for a frame callback then we'll at least throttle
2460    * to a sync callback so that we always give a chance for the compositor to
2461    * handle the commit and send a release event before checking for a free
2462    * buffer */
2463   if (dri2_surf->throttle_callback == NULL) {
2464      dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
2465      wl_callback_add_listener(dri2_surf->throttle_callback,
2466                               &throttle_listener, dri2_surf);
2467   }
2468
2469   wl_display_flush(dri2_dpy->wl_dpy);
2470}
2471
2472static void
2473dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,
2474                                 int *x, int *y, int *w, int *h,
2475                                 void *loaderPrivate)
2476{
2477   struct dri2_egl_surface *dri2_surf = loaderPrivate;
2478
2479   (void) swrast_update_buffers(dri2_surf);
2480   *x = 0;
2481   *y = 0;
2482   *w = dri2_surf->base.Width;
2483   *h = dri2_surf->base.Height;
2484}
2485
2486static void
2487dri2_wl_swrast_get_image(__DRIdrawable * read,
2488                         int x, int y, int w, int h,
2489                         char *data, void *loaderPrivate)
2490{
2491   struct dri2_egl_surface *dri2_surf = loaderPrivate;
2492   int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
2493   int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
2494   int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
2495   int dst_stride = copy_width;
2496   char *src, *dst;
2497
2498   src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);
2499   if (!src) {
2500      memset(data, 0, copy_width * h);
2501      return;
2502   }
2503
2504   assert(data != src);
2505   assert(copy_width <= src_stride);
2506
2507   src += x_offset;
2508   src += y * src_stride;
2509   dst = data;
2510
2511   if (copy_width > src_stride-x_offset)
2512      copy_width = src_stride-x_offset;
2513   if (h > dri2_surf->base.Height-y)
2514      h = dri2_surf->base.Height-y;
2515
2516   for (; h>0; h--) {
2517      memcpy(dst, src, copy_width);
2518      src += src_stride;
2519      dst += dst_stride;
2520   }
2521}
2522
2523static void
2524dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,
2525                         int x, int y, int w, int h, int stride,
2526                         char *data, void *loaderPrivate)
2527{
2528   struct dri2_egl_surface *dri2_surf = loaderPrivate;
2529   int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
2530   int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
2531   int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
2532   char *src, *dst;
2533
2534   assert(copy_width <= stride);
2535
2536   (void) swrast_update_buffers(dri2_surf);
2537   dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
2538
2539   /* partial copy, copy old content */
2540   if (copy_width < dst_stride)
2541      dri2_wl_swrast_get_image(draw, 0, 0,
2542                               dri2_surf->base.Width, dri2_surf->base.Height,
2543                               dst, loaderPrivate);
2544
2545   dst += x_offset;
2546   dst += y * dst_stride;
2547
2548   src = data;
2549
2550   /* drivers expect we do these checks (and some rely on it) */
2551   if (copy_width > dst_stride-x_offset)
2552      copy_width = dst_stride-x_offset;
2553   if (h > dri2_surf->base.Height-y)
2554      h = dri2_surf->base.Height-y;
2555
2556   for (; h>0; h--) {
2557      memcpy(dst, src, copy_width);
2558      src += stride;
2559      dst += dst_stride;
2560   }
2561   dri2_wl_swrast_commit_backbuffer(dri2_surf);
2562}
2563
2564static void
2565dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,
2566                         int x, int y, int w, int h,
2567                         char *data, void *loaderPrivate)
2568{
2569   struct dri2_egl_surface *dri2_surf = loaderPrivate;
2570   int stride;
2571
2572   stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
2573   dri2_wl_swrast_put_image2(draw, op, x, y, w, h,
2574                             stride, data, loaderPrivate);
2575}
2576
2577static EGLBoolean
2578dri2_wl_swrast_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
2579{
2580   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2581   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
2582
2583   if (!dri2_surf->wl_win)
2584      return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");
2585
2586   dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
2587   if (disp->Options.Zink) {
2588      dri2_surf->current = dri2_surf->back;
2589      dri2_surf->back = NULL;
2590   }
2591   return EGL_TRUE;
2592}
2593
2594static void
2595shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
2596{
2597   struct dri2_egl_display *dri2_dpy = data;
2598   int visual_idx = dri2_wl_visual_idx_from_shm_format(format);
2599
2600   if (visual_idx == -1)
2601      return;
2602
2603   BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx);
2604}
2605
2606static const struct wl_shm_listener shm_listener = {
2607   .format = shm_handle_format
2608};
2609
2610static void
2611registry_handle_global_swrast(void *data, struct wl_registry *registry,
2612                              uint32_t name, const char *interface,
2613                              uint32_t version)
2614{
2615   struct dri2_egl_display *dri2_dpy = data;
2616
2617   if (strcmp(interface, "wl_shm") == 0) {
2618      dri2_dpy->wl_shm =
2619         wl_registry_bind(registry, name, &wl_shm_interface, 1);
2620      wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);
2621   }
2622}
2623
2624static const struct wl_registry_listener registry_listener_swrast = {
2625   .global = registry_handle_global_swrast,
2626   .global_remove = registry_handle_global_remove
2627};
2628
2629static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
2630   .authenticate = NULL,
2631   .create_window_surface = dri2_wl_create_window_surface,
2632   .create_pixmap_surface = dri2_wl_create_pixmap_surface,
2633   .destroy_surface = dri2_wl_destroy_surface,
2634   .create_image = dri2_create_image_khr,
2635   .swap_buffers = dri2_wl_swrast_swap_buffers,
2636   .get_dri_drawable = dri2_surface_get_dri_drawable,
2637};
2638
2639static const __DRIswrastLoaderExtension swrast_loader_extension = {
2640   .base = { __DRI_SWRAST_LOADER, 2 },
2641
2642   .getDrawableInfo = dri2_wl_swrast_get_drawable_info,
2643   .putImage        = dri2_wl_swrast_put_image,
2644   .getImage        = dri2_wl_swrast_get_image,
2645   .putImage2       = dri2_wl_swrast_put_image2,
2646};
2647
2648static void
2649kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *out)
2650{
2651    struct dri2_egl_surface *dri2_surf = _draw;
2652    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
2653    VkWaylandSurfaceCreateInfoKHR *wlsci = &out->wl;
2654
2655    wlsci->sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2656    wlsci->pNext = NULL;
2657    wlsci->flags = 0;
2658    wlsci->display = dri2_dpy->wl_dpy;
2659    wlsci->surface = dri2_surf->wl_surface_wrapper;
2660}
2661
2662static const __DRIkopperLoaderExtension kopper_loader_extension = {
2663    .base = { __DRI_KOPPER_LOADER, 1 },
2664
2665    .SetSurfaceCreateInfo   = kopperSetSurfaceCreateInfo,
2666};
2667static const __DRIextension *swrast_loader_extensions[] = {
2668   &swrast_loader_extension.base,
2669   &image_lookup_extension.base,
2670   &kopper_loader_extension.base,
2671   NULL,
2672};
2673
2674static EGLBoolean
2675dri2_initialize_wayland_swrast(_EGLDisplay *disp)
2676{
2677   _EGLDevice *dev;
2678   struct dri2_egl_display *dri2_dpy;
2679
2680   dri2_dpy = calloc(1, sizeof *dri2_dpy);
2681   if (!dri2_dpy)
2682      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
2683
2684   dri2_dpy->fd = -1;
2685   disp->DriverData = (void *) dri2_dpy;
2686
2687   if (dri2_wl_formats_init(&dri2_dpy->formats) < 0)
2688      goto cleanup;
2689
2690   if (disp->PlatformDisplay == NULL) {
2691      dri2_dpy->wl_dpy = wl_display_connect(NULL);
2692      if (dri2_dpy->wl_dpy == NULL)
2693         goto cleanup;
2694      dri2_dpy->own_device = true;
2695   } else {
2696      dri2_dpy->wl_dpy = disp->PlatformDisplay;
2697   }
2698
2699   dev = _eglAddDevice(dri2_dpy->fd, true);
2700   if (!dev) {
2701      _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
2702      goto cleanup;
2703   }
2704
2705   disp->Device = dev;
2706
2707   dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
2708
2709   dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
2710   if (dri2_dpy->wl_dpy_wrapper == NULL)
2711      goto cleanup;
2712
2713   wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
2714                      dri2_dpy->wl_queue);
2715
2716   if (dri2_dpy->own_device)
2717      wl_display_dispatch_pending(dri2_dpy->wl_dpy);
2718
2719   dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
2720   wl_registry_add_listener(dri2_dpy->wl_registry,
2721                            &registry_listener_swrast, dri2_dpy);
2722
2723   if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
2724      goto cleanup;
2725
2726   if (roundtrip(dri2_dpy) < 0 || !BITSET_TEST_RANGE(dri2_dpy->formats.formats_bitmap,
2727                                                     0, dri2_dpy->formats.num_formats))
2728      goto cleanup;
2729
2730   dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast");
2731   if (!dri2_load_driver_swrast(disp))
2732      goto cleanup;
2733
2734   dri2_dpy->loader_extensions = swrast_loader_extensions;
2735
2736   if (!dri2_create_screen(disp))
2737      goto cleanup;
2738
2739   if (!dri2_setup_extensions(disp))
2740      goto cleanup;
2741
2742   dri2_setup_screen(disp);
2743
2744   dri2_wl_setup_swap_interval(disp);
2745
2746   if (!dri2_wl_add_configs_for_visuals(disp)) {
2747      _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
2748      goto cleanup;
2749   }
2750
2751   /* Fill vtbl last to prevent accidentally calling virtual function during
2752    * initialization.
2753    */
2754   dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
2755
2756   return EGL_TRUE;
2757
2758 cleanup:
2759   dri2_display_destroy(disp);
2760   return EGL_FALSE;
2761}
2762
2763EGLBoolean
2764dri2_initialize_wayland(_EGLDisplay *disp)
2765{
2766   if (disp->Options.ForceSoftware)
2767      return dri2_initialize_wayland_swrast(disp);
2768   else
2769      return dri2_initialize_wayland_drm(disp);
2770}
2771
2772void
2773dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
2774{
2775   dri2_wl_formats_fini(&dri2_dpy->formats);
2776   if (dri2_dpy->wl_drm)
2777      wl_drm_destroy(dri2_dpy->wl_drm);
2778   if (dri2_dpy->wl_dmabuf)
2779      zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
2780   if (dri2_dpy->wl_shm)
2781      wl_shm_destroy(dri2_dpy->wl_shm);
2782   if (dri2_dpy->wl_registry)
2783      wl_registry_destroy(dri2_dpy->wl_registry);
2784   if (dri2_dpy->wl_queue)
2785      wl_event_queue_destroy(dri2_dpy->wl_queue);
2786   if (dri2_dpy->wl_dpy_wrapper)
2787      wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
2788
2789   if (dri2_dpy->own_device)
2790      wl_display_disconnect(dri2_dpy->wl_dpy);
2791}
2792