platform_wayland.c 68.9 KB
Newer Older
1
/*
2
 * Copyright © 2011-2012 Intel Corporation
3
 * Copyright © 2012 Collabora, Ltd.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Kristian Høgsberg <krh@bitplanet.net>
 *    Benjamin Franzke <benjaminfranzke@googlemail.com>
 */

30
#include <stdint.h>
31
32
33
34
35
36
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <dlfcn.h>
#include <errno.h>
#include <unistd.h>
37
38
#include <fcntl.h>
#include <xf86drm.h>
39
#include "drm-uapi/drm_fourcc.h"
40
#include <sys/mman.h>
41
42

#include "egl_dri2.h"
Emil Velikov's avatar
Emil Velikov committed
43
#include "loader.h"
44
#include "util/u_vector.h"
45
#include "util/anon_file.h"
46
#include "eglglobals.h"
47

48
#include <wayland-egl-backend.h>
49
50
#include <wayland-client.h>
#include "wayland-drm-client-protocol.h"
51
52
#include "linux-dmabuf-unstable-v1-client-protocol.h"

53
54
55
56
57
58
59
/* cheesy workaround until wayland 1.18 is released */
#if WAYLAND_VERSION_MAJOR > 1 || \
   (WAYLAND_VERSION_MAJOR == 1 && WAYLAND_VERSION_MINOR < 18)
#define WL_SHM_FORMAT_ABGR16161616F 0x48344241
#define WL_SHM_FORMAT_XBGR16161616F 0x48344258
#endif

60
61
62
63
/*
 * The index of entries in this table is used as a bitmask in
 * dri2_dpy->formats, which tracks the formats supported by our server.
 */
64
static const struct dri2_wl_visual {
65
   const char *format_name;
66
67
68
   uint32_t wl_drm_format;
   uint32_t wl_shm_format;
   int dri_image_format;
69
70
71
72
73
74
75
76
   /* alt_dri_image_format is a substitute wl_buffer format to use for a
    * wl-server unsupported dri_image_format, ie. some other dri_image_format in
    * the table, of the same precision but with different channel ordering, or
    * __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported.
    * The code checks if alt_dri_image_format can be used as a fallback for a
    * dri_image_format for a given wl-server implementation.
    */
   int alt_dri_image_format;
77
   int bpp;
78
79
   int rgba_shifts[4];
   unsigned int rgba_sizes[4];
80
} dri2_wl_visuals[] = {
81
82
83
84
85
86
87
88
89
90
91
92
93
94
   {
      "ABGR16F",
      WL_DRM_FORMAT_ABGR16F, WL_SHM_FORMAT_ABGR16161616F,
      __DRI_IMAGE_FORMAT_ABGR16161616F, 0, 64,
      { 0, 16, 32, 48 },
      { 16, 16, 16, 16 },
   },
   {
      "XBGR16F",
      WL_DRM_FORMAT_XBGR16F, WL_SHM_FORMAT_XBGR16161616F,
      __DRI_IMAGE_FORMAT_XBGR16161616F, 0, 64,
      { 0, 16, 32, -1 },
      { 16, 16, 16, 0 },
   },
95
   {
96
97
98
99
100
      "XRGB2101010",
      WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010,
      __DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32,
      { 20, 10, 0, -1 },
      { 10, 10, 10, 0 },
101
102
   },
   {
103
104
105
106
107
      "ARGB2101010",
      WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010,
      __DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32,
      { 20, 10, 0, 30 },
      { 10, 10, 10, 2 },
108
   },
109
   {
110
111
112
113
114
      "XBGR2101010",
      WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010,
      __DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32,
      { 0, 10, 20, -1 },
      { 10, 10, 10, 0 },
115
116
   },
   {
117
118
119
120
121
      "ABGR2101010",
      WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010,
      __DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32,
      { 0, 10, 20, 30 },
      { 10, 10, 10, 2 },
122
   },
123
   {
124
125
126
127
128
      "XRGB8888",
      WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888,
      __DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
      { 16, 8, 0, -1 },
      { 8, 8, 8, 0 },
129
130
   },
   {
131
132
133
134
135
      "ARGB8888",
      WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888,
      __DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
      { 16, 8, 0, 24 },
      { 8, 8, 8, 8 },
136
137
   },
   {
138
139
140
141
142
      "RGB565",
      WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565,
      __DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16,
      { 11, 5, 0, -1 },
      { 5, 6, 5, 0 },
143
   },
144
145
};

146
147
148
149
static_assert(ARRAY_SIZE(dri2_wl_visuals) <= EGL_DRI2_MAX_FORMATS,
              "dri2_egl_display::formats is not large enough for "
              "the formats in dri2_wl_visuals");

150
151
152
153
static int
dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy,
                               const __DRIconfig *config)
{
154
155
   int shifts[4];
   unsigned int sizes[4];
156

157
   dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
158

159
   for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
160
161
      const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i];

162
163
164
165
166
167
168
169
      if (shifts[0] == wl_visual->rgba_shifts[0] &&
          shifts[1] == wl_visual->rgba_shifts[1] &&
          shifts[2] == wl_visual->rgba_shifts[2] &&
          shifts[3] == wl_visual->rgba_shifts[3] &&
          sizes[0] == wl_visual->rgba_sizes[0] &&
          sizes[1] == wl_visual->rgba_sizes[1] &&
          sizes[2] == wl_visual->rgba_sizes[2] &&
          sizes[3] == wl_visual->rgba_sizes[3]) {
170
171
172
173
174
175
176
         return i;
      }
   }

   return -1;
}

177
178
179
180
181
182
183
184
185
186
187
188
189
static int
dri2_wl_visual_idx_from_fourcc(uint32_t fourcc)
{
   for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
      /* wl_drm format codes overlap with DRIImage FourCC codes for all formats
       * we support. */
      if (dri2_wl_visuals[i].wl_drm_format == fourcc)
         return i;
   }

   return -1;
}

190
191
192
193
194
195
196
197
198
199
200
static int
dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format)
{
   for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
      if (dri2_wl_visuals[i].dri_image_format == dri_image_format)
         return i;
   }

   return -1;
}

201
202
203
204
205
206
207
208
209
210
211
static int
dri2_wl_visual_idx_from_shm_format(uint32_t shm_format)
{
   for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
      if (dri2_wl_visuals[i].wl_shm_format == shm_format)
         return i;
   }

   return -1;
}

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
bool
dri2_wl_is_format_supported(void* user_data, uint32_t format)
{
   _EGLDisplay *disp = (_EGLDisplay *) user_data;
   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   int j = dri2_wl_visual_idx_from_fourcc(format);

   if (j == -1)
      return false;

   for (int i = 0; dri2_dpy->driver_configs[i]; i++)
      if (j == dri2_wl_visual_idx_from_config(dri2_dpy,
                                              dri2_dpy->driver_configs[i]))
         return true;

   return false;
}

230
231
232
static int
roundtrip(struct dri2_egl_display *dri2_dpy)
{
233
   return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
234
235
}

236
237
238
239
240
241
static void
wl_buffer_release(void *data, struct wl_buffer *buffer)
{
   struct dri2_egl_surface *dri2_surf = data;
   int i;

242
243
   for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
      if (dri2_surf->color_buffers[i].wl_buffer == buffer)
244
245
         break;

246
247
248
   assert (i < ARRAY_SIZE(dri2_surf->color_buffers));

   if (dri2_surf->color_buffers[i].wl_release) {
249
      wl_buffer_destroy(buffer);
250
251
      dri2_surf->color_buffers[i].wl_release = false;
      dri2_surf->color_buffers[i].wl_buffer = NULL;
252
   }
253

254
   dri2_surf->color_buffers[i].locked = false;
255
256
}

257
258
static const struct wl_buffer_listener wl_buffer_listener = {
   .release = wl_buffer_release
259
};
260

261
262
263
264
265
266
267
static void
resize_callback(struct wl_egl_window *wl_win, void *data)
{
   struct dri2_egl_surface *dri2_surf = data;
   struct dri2_egl_display *dri2_dpy =
      dri2_egl_display(dri2_surf->base.Resource.Display);

268
269
270
271
   if (dri2_surf->base.Width == wl_win->width &&
       dri2_surf->base.Height == wl_win->height)
      return;

272
   /* Update the surface size as soon as native window is resized; from user
Eric Engestrom's avatar
Eric Engestrom committed
273
    * pov, this makes the effect that resize is done immediately after native
274
275
276
277
278
279
280
281
282
    * window resize, without requiring to wait until the first draw.
    *
    * A more detailed and lengthy explanation can be found at
    * https://lists.freedesktop.org/archives/mesa-dev/2018-June/196474.html
    */
   if (!dri2_surf->back) {
      dri2_surf->base.Width = wl_win->width;
      dri2_surf->base.Height = wl_win->height;
   }
283
   dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
284
285
}

286
287
288
289
290
291
292
static void
destroy_window_callback(void *data)
{
   struct dri2_egl_surface *dri2_surf = data;
   dri2_surf->wl_win = NULL;
}

293
294
295
296
297
static struct wl_surface *
get_wl_surface_proxy(struct wl_egl_window *window)
{
    /* Version 3 of wl_egl_window introduced a version field at the same
     * location where a pointer to wl_surface was stored. Thus, if
Eric Engestrom's avatar
Eric Engestrom committed
298
     * window->version is dereferenceable, we've been given an older version of
299
300
301
302
303
304
305
     * wl_egl_window, and window->version points to wl_surface */
   if (_eglPointerIsDereferencable((void *)(window->version))) {
      return wl_proxy_create_wrapper((void *)(window->version));
   }
   return wl_proxy_create_wrapper(window->surface);
}

306
/**
307
 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
308
309
 */
static _EGLSurface *
310
311
312
dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
                              _EGLConfig *conf, void *native_window,
                              const EGLint *attrib_list)
313
314
315
{
   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
316
   struct wl_egl_window *window = native_window;
317
   struct dri2_egl_surface *dri2_surf;
318
   int visual_idx;
319
   const __DRIconfig *config;
320

321
   dri2_surf = calloc(1, sizeof *dri2_surf);
322
323
324
325
   if (!dri2_surf) {
      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
      return NULL;
   }
326

327
   if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
328
                          attrib_list, false, native_window))
329
330
      goto cleanup_surf;

331
332
   config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
                                dri2_surf->base.GLColorspace);
333
334
335
336
337
338

   if (!config) {
      _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
      goto cleanup_surf;
   }

339
340
341
   dri2_surf->base.Width = window->width;
   dri2_surf->base.Height = window->height;

342
343
344
   visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config);
   assert(visual_idx != -1);

345
   if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {
346
      dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format;
347
   } else {
348
      assert(dri2_dpy->wl_shm);
349
      dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format;
350
   }
351

352
   dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
353
   if (!dri2_surf->wl_queue) {
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
      goto cleanup_surf;
   }

   if (dri2_dpy->wl_drm) {
      dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);
      if (!dri2_surf->wl_drm_wrapper) {
         _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
         goto cleanup_queue;
      }
      wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,
                         dri2_surf->wl_queue);
   }

   dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
   if (!dri2_surf->wl_dpy_wrapper) {
      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
      goto cleanup_drm;
   }
   wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,
                      dri2_surf->wl_queue);

376
   dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window);
377
378
   if (!dri2_surf->wl_surface_wrapper) {
      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
379
      goto cleanup_dpy_wrapper;
380
381
382
   }
   wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
                      dri2_surf->wl_queue);
383

384
   dri2_surf->wl_win = window;
385
   dri2_surf->wl_win->driver_private = dri2_surf;
386
   dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
387
388
   if (dri2_dpy->flush)
      dri2_surf->wl_win->resize_callback = resize_callback;
389

390
   if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
391
       goto cleanup_surf_wrapper;
392

393
   dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
394

395
396
   return &dri2_surf->base;

397
398
399
400
 cleanup_surf_wrapper:
   wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
 cleanup_dpy_wrapper:
   wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
401
402
403
404
405
 cleanup_drm:
   if (dri2_surf->wl_drm_wrapper)
      wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
 cleanup_queue:
   wl_event_queue_destroy(dri2_surf->wl_queue);
406
407
408
409
410
411
 cleanup_surf:
   free(dri2_surf);

   return NULL;
}

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
static _EGLSurface *
dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
                              _EGLConfig *conf, void *native_window,
                              const EGLint *attrib_list)
{
   /* From the EGL_EXT_platform_wayland spec, version 3:
    *
    *   It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
    *   that belongs to Wayland. Any such call fails and generates
    *   EGL_BAD_PARAMETER.
    */
   _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
             "Wayland");
   return NULL;
}

428
/**
429
 * Called via eglDestroySurface(), drv->DestroySurface().
430
431
 */
static EGLBoolean
432
dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
433
434
435
436
437
438
{
   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);

   (void) drv;

439
   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
440

441
   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
442
443
      if (dri2_surf->color_buffers[i].wl_buffer)
         wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
444
445
      if (dri2_surf->color_buffers[i].dri_image)
         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
446
447
      if (dri2_surf->color_buffers[i].linear_copy)
         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
448
449
450
      if (dri2_surf->color_buffers[i].data)
         munmap(dri2_surf->color_buffers[i].data,
                dri2_surf->color_buffers[i].data_size);
451
   }
452

453
454
   if (dri2_dpy->dri2)
      dri2_egl_surface_free_local_buffers(dri2_surf);
455

456
457
   if (dri2_surf->throttle_callback)
      wl_callback_destroy(dri2_surf->throttle_callback);
458

459
   if (dri2_surf->wl_win) {
460
      dri2_surf->wl_win->driver_private = NULL;
461
462
463
      dri2_surf->wl_win->resize_callback = NULL;
      dri2_surf->wl_win->destroy_window_callback = NULL;
   }
464

465
466
   wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
   wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
467
468
   if (dri2_surf->wl_drm_wrapper)
      wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
469
470
   wl_event_queue_destroy(dri2_surf->wl_queue);

471
   dri2_fini_surface(surf);
472
473
474
475
476
477
   free(surf);

   return EGL_TRUE;
}

static void
478
dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
479
480
481
482
{
   struct dri2_egl_display *dri2_dpy =
      dri2_egl_display(dri2_surf->base.Resource.Display);

483
   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
484
485
486
487
488
489
490
491
      if (dri2_surf->color_buffers[i].wl_buffer) {
         if (dri2_surf->color_buffers[i].locked) {
            dri2_surf->color_buffers[i].wl_release = true;
         } else {
            wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
            dri2_surf->color_buffers[i].wl_buffer = NULL;
         }
      }
492
493
      if (dri2_surf->color_buffers[i].dri_image)
         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
494
495
      if (dri2_surf->color_buffers[i].linear_copy)
         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
496
497
498
      if (dri2_surf->color_buffers[i].data)
         munmap(dri2_surf->color_buffers[i].data,
                dri2_surf->color_buffers[i].data_size);
499

500
      dri2_surf->color_buffers[i].dri_image = NULL;
501
      dri2_surf->color_buffers[i].linear_copy = NULL;
502
      dri2_surf->color_buffers[i].data = NULL;
503
   }
504

505
506
   if (dri2_dpy->dri2)
      dri2_egl_surface_free_local_buffers(dri2_surf);
507
508
}

509
static int
510
get_back_bo(struct dri2_egl_surface *dri2_surf)
511
512
513
{
   struct dri2_egl_display *dri2_dpy =
      dri2_egl_display(dri2_surf->base.Resource.Display);
514
   int use_flags;
515
   int visual_idx;
516
   unsigned int dri_image_format;
517
   unsigned int linear_dri_image_format;
518
519
   uint64_t *modifiers;
   int num_modifiers;
520

521
522
523
   visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
   assert(visual_idx != -1);
   dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format;
524
   linear_dri_image_format = dri_image_format;
525
526
   modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]);
   num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]);
527

528
529
530
531
532
533
534
   if (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
      /* For the purposes of this function, an INVALID modifier on its own
       * means the modifiers aren't supported.
       */
      num_modifiers = 0;
   }

535
   /* Substitute dri image format if server does not support original format */
536
   if (!BITSET_TEST(dri2_dpy->formats, visual_idx))
537
538
539
540
541
542
543
      linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format;

   /* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and
    * the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free
    * of bugs.
    */
   assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE);
544
545
   assert(BITSET_TEST(dri2_dpy->formats,
          dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format)));
546

547
   /* There might be a buffer release already queued that wasn't processed */
548
   wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
549

550
   while (dri2_surf->back == NULL) {
551
      for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
Eric Engestrom's avatar
Eric Engestrom committed
552
         /* Get an unlocked buffer, preferably one with a dri_buffer
553
554
          * already allocated. */
         if (dri2_surf->color_buffers[i].locked)
555
556
            continue;
         if (dri2_surf->back == NULL)
557
            dri2_surf->back = &dri2_surf->color_buffers[i];
558
         else if (dri2_surf->back->dri_image == NULL)
559
            dri2_surf->back = &dri2_surf->color_buffers[i];
560
      }
561
562
563
564
565

      if (dri2_surf->back)
         break;

      /* If we don't have a buffer, then block on the server to release one for
566
567
568
569
570
571
572
       * us, and try again. wl_display_dispatch_queue will process any pending
       * events, however not all servers flush on issuing a buffer release
       * event. So, we spam the server with roundtrips as they always cause a
       * client flush.
       */
      if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,
                                     dri2_surf->wl_queue) < 0)
573
          return -1;
574
   }
575

576
577
   if (dri2_surf->back == NULL)
      return -1;
578

Axel Davy's avatar
Axel Davy committed
579
580
   use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;

581
582
   if (dri2_dpy->is_different_gpu &&
       dri2_surf->back->linear_copy == NULL) {
583
584
585
586
587
588
589
590
591
592
      /* The LINEAR modifier should be a perfect alias of the LINEAR use
       * flag; try the new interface first before the old, then fall back. */
      if (dri2_dpy->image->base.version >= 15 &&
           dri2_dpy->image->createImageWithModifiers) {
         uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;

         dri2_surf->back->linear_copy =
            dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
                                                      dri2_surf->base.Width,
                                                      dri2_surf->base.Height,
593
                                                      linear_dri_image_format,
594
595
596
597
598
599
600
601
                                                      &linear_mod,
                                                      1,
                                                      NULL);
      } else {
         dri2_surf->back->linear_copy =
            dri2_dpy->image->createImage(dri2_dpy->dri_screen,
                                         dri2_surf->base.Width,
                                         dri2_surf->base.Height,
602
                                         linear_dri_image_format,
603
604
605
606
                                         use_flags |
                                         __DRI_IMAGE_USE_LINEAR,
                                         NULL);
      }
607
608
609
610
      if (dri2_surf->back->linear_copy == NULL)
          return -1;
   }

611
   if (dri2_surf->back->dri_image == NULL) {
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
      /* If our DRIImage implementation does not support
       * createImageWithModifiers, then fall back to the old createImage,
       * and hope it allocates an image which is acceptable to the winsys.
        */
      if (num_modifiers && dri2_dpy->image->base.version >= 15 &&
          dri2_dpy->image->createImageWithModifiers) {
         dri2_surf->back->dri_image =
           dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
                                                     dri2_surf->base.Width,
                                                     dri2_surf->base.Height,
                                                     dri_image_format,
                                                     modifiers,
                                                     num_modifiers,
                                                     NULL);
      } else {
         dri2_surf->back->dri_image =
            dri2_dpy->image->createImage(dri2_dpy->dri_screen,
                                         dri2_surf->base.Width,
                                         dri2_surf->base.Height,
                                         dri_image_format,
                                         dri2_dpy->is_different_gpu ?
                                              0 : use_flags,
                                         NULL);
      }

637
      dri2_surf->back->age = 0;
638
   }
639
   if (dri2_surf->back->dri_image == NULL)
640
      return -1;
641

642
   dri2_surf->back->locked = true;
643
644
645
646
647
648
649
650
651
652
653
654
655

   return 0;
}


static void
back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
{
   struct dri2_egl_display *dri2_dpy =
      dri2_egl_display(dri2_surf->base.Resource.Display);
   __DRIimage *image;
   int name, pitch;

656
657
658
659
660
661
662
663
664
665
   image = dri2_surf->back->dri_image;

   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);

   buffer->attachment = __DRI_BUFFER_BACK_LEFT;
   buffer->name = name;
   buffer->pitch = pitch;
   buffer->cpp = 4;
   buffer->flags = 0;
666
667
}

668
669
static int
update_buffers(struct dri2_egl_surface *dri2_surf)
670
671
672
{
   struct dri2_egl_display *dri2_dpy =
      dri2_egl_display(dri2_surf->base.Resource.Display);
673

674
675
   if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
       dri2_surf->base.Height != dri2_surf->wl_win->height) {
676
677
678
679
680

      dri2_surf->base.Width  = dri2_surf->wl_win->width;
      dri2_surf->base.Height = dri2_surf->wl_win->height;
      dri2_surf->dx = dri2_surf->wl_win->dx;
      dri2_surf->dy = dri2_surf->wl_win->dy;
681
   }
682

683
684
685
686
687
   if (dri2_surf->base.Width != dri2_surf->wl_win->attached_width ||
       dri2_surf->base.Height != dri2_surf->wl_win->attached_height) {
      dri2_wl_release_buffers(dri2_surf);
   }

688
689
690
   if (get_back_bo(dri2_surf) < 0) {
      _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
      return -1;
691
692
   }

693
694
695
   /* If we have an extra unlocked buffer at this point, we had to do triple
    * buffering for a while, but now can go back to just double buffering.
    * That means we can free any unlocked buffer now. */
696
   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
697
698
699
      if (!dri2_surf->color_buffers[i].locked &&
          dri2_surf->color_buffers[i].wl_buffer) {
         wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
700
         dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
701
702
         if (dri2_dpy->is_different_gpu)
            dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
703
         dri2_surf->color_buffers[i].wl_buffer = NULL;
704
         dri2_surf->color_buffers[i].dri_image = NULL;
705
         dri2_surf->color_buffers[i].linear_copy = NULL;
706
707
708
      }
   }

709
710
711
   return 0;
}

712
713
714
715
716
717
718
719
720
static int
update_buffers_if_needed(struct dri2_egl_surface *dri2_surf)
{
   if (dri2_surf->back != NULL)
      return 0;

   return update_buffers(dri2_surf);
}

721
static __DRIbuffer *
722
723
724
725
dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
                                int *width, int *height,
                                unsigned int *attachments, int count,
                                int *out_count, void *loaderPrivate)
726
727
728
729
730
731
732
733
{
   struct dri2_egl_surface *dri2_surf = loaderPrivate;
   int i, j;

   if (update_buffers(dri2_surf) < 0)
      return NULL;

   for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
734
735
      __DRIbuffer *local;

736
737
738
      switch (attachments[i]) {
      case __DRI_BUFFER_BACK_LEFT:
         back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
739
         break;
740
      default:
741
742
743
744
745
         local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
                                                     attachments[i + 1]);

         if (!local) {
            _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
746
747
            return NULL;
         }
748
         dri2_surf->buffers[j] = *local;
749
         break;
750
751
752
      }
   }

753
754
   *out_count = j;
   if (j == 0)
755
      return NULL;
756
757
758
759
760
761
762
763

   *width = dri2_surf->base.Width;
   *height = dri2_surf->base.Height;

   return dri2_surf->buffers;
}

static __DRIbuffer *
764
765
766
767
dri2_wl_get_buffers(__DRIdrawable * driDrawable,
                    int *width, int *height,
                    unsigned int *attachments, int count,
                    int *out_count, void *loaderPrivate)
768
{
769
   struct dri2_egl_surface *dri2_surf = loaderPrivate;
770
771
   unsigned int *attachments_with_format;
   __DRIbuffer *buffer;
772
   int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
773

774
   if (visual_idx == -1)
775
776
      return NULL;

777
   attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
778
779
780
781
782
   if (!attachments_with_format) {
      *out_count = 0;
      return NULL;
   }

783
   for (int i = 0; i < count; ++i) {
784
      attachments_with_format[2*i] = attachments[i];
785
      attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].bpp;
786
787
788
   }

   buffer =
789
790
791
792
      dri2_wl_get_buffers_with_format(driDrawable,
                                      width, height,
                                      attachments_with_format, count,
                                      out_count, loaderPrivate);
793
794
795
796
797
798

   free(attachments_with_format);

   return buffer;
}

799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
static int
image_get_buffers(__DRIdrawable *driDrawable,
                  unsigned int format,
                  uint32_t *stamp,
                  void *loaderPrivate,
                  uint32_t buffer_mask,
                  struct __DRIimageList *buffers)
{
   struct dri2_egl_surface *dri2_surf = loaderPrivate;

   if (update_buffers(dri2_surf) < 0)
      return 0;

   buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
   buffers->back = dri2_surf->back->dri_image;

   return 1;
}

818
static void
819
dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
820
821
822
823
824
{
   (void) driDrawable;
   (void) loaderPrivate;
}

825
826
827
828
829
830
831
832
833
834
835
static unsigned
dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
{
   switch (cap) {
   case DRI_LOADER_CAP_FP16:
      return 1;
   default:
      return 0;
   }
}

836
static const __DRIdri2LoaderExtension dri2_loader_extension = {
837
   .base = { __DRI_DRI2_LOADER, 4 },
838
839
840
841

   .getBuffers           = dri2_wl_get_buffers,
   .flushFrontBuffer     = dri2_wl_flush_front_buffer,
   .getBuffersWithFormat = dri2_wl_get_buffers_with_format,
842
   .getCapability        = dri2_wl_get_capability,
843
844
};

845
static const __DRIimageLoaderExtension image_loader_extension = {
846
   .base = { __DRI_IMAGE_LOADER, 2 },
847
848

   .getBuffers          = image_get_buffers,
849
   .flushFrontBuffer    = dri2_wl_flush_front_buffer,
850
   .getCapability       = dri2_wl_get_capability,
851
852
};

853
static void
854
855
856
wayland_throttle_callback(void *data,
                          struct wl_callback *callback,
                          uint32_t time)
857
858
859
{
   struct dri2_egl_surface *dri2_surf = data;

860
   dri2_surf->throttle_callback = NULL;
861
   wl_callback_destroy(callback);
862
863
}

864
static const struct wl_callback_listener throttle_listener = {
865
   .done = wayland_throttle_callback
866
867
};

868
869
870
871
872
static EGLBoolean
get_fourcc(struct dri2_egl_display *dri2_dpy,
           __DRIimage *image, int *fourcc)
{
   EGLBoolean query;
Eric Engestrom's avatar
Eric Engestrom committed
873
   int dri_format;
874
   int visual_idx;
875
876
877
878
879
880
881
882
883
884
885

   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,
                                       fourcc);
   if (query)
      return true;

   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,
                                       &dri_format);
   if (!query)
      return false;

886
887
   visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format);
   if (visual_idx == -1)
888
      return false;
889
890
891

   *fourcc = dri2_wl_visuals[visual_idx].wl_drm_format;
   return true;
892
893
}

894
895
896
897
static struct wl_buffer *
create_wl_buffer(struct dri2_egl_display *dri2_dpy,
                 struct dri2_egl_surface *dri2_surf,
                 __DRIimage *image)
898
{
899
   struct wl_buffer *ret;
900
   EGLBoolean query;
901
   int width, height, fourcc, num_planes;
902
   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
903

904
905
906
   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
   query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,
                                        &height);
907
   query &= get_fourcc(dri2_dpy, image, &fourcc);
908
909
910
911
912
913
914
   if (!query)
      return NULL;

   query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
                                       &num_planes);
   if (!query)
      num_planes = 1;
915

916
   if (dri2_dpy->image->base.version >= 15) {
917
918
      int mod_hi, mod_lo;

919
920
921
922
923
924
      query = dri2_dpy->image->queryImage(image,
                                          __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
                                          &mod_hi);
      query &= dri2_dpy->image->queryImage(image,
                                           __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
                                           &mod_lo);
925
      if (query) {
926
         modifier = combine_u32_into_u64(mod_hi, mod_lo);
927
      }
928
929
   }

930
   bool supported_modifier = false;
931
932
933
934
935
936
937
938
   bool mod_invalid_supported = false;
   int visual_idx = dri2_wl_visual_idx_from_fourcc(fourcc);
   assert(visual_idx != -1);

   uint64_t *mod;
   u_vector_foreach(mod, &dri2_dpy->wl_modifiers[visual_idx]) {
      if (*mod == DRM_FORMAT_MOD_INVALID) {
         mod_invalid_supported = true;
939
      }
940
941
942
943
944
945
946
947
948
949
950
951
      if (*mod == modifier) {
         supported_modifier = true;
         break;
      }
   }
   if (!supported_modifier && mod_invalid_supported) {
      /* If the server has advertised DRM_FORMAT_MOD_INVALID then we trust
       * that the client has allocated the buffer with the right implicit
       * modifier for the format, even though it's allocated a buffer the
       * server hasn't explicitly claimed to support. */
      modifier = DRM_FORMAT_MOD_INVALID;
      supported_modifier = true;
952
953
954
   }

   if (dri2_dpy->wl_dmabuf && supported_modifier) {
955
956
      struct zwp_linux_buffer_params_v1 *params;
      int i;
957
958
959
960
961
962
963
964
965
966

      /* We don't need a wrapper for wl_dmabuf objects, because we have to
       * create the intermediate params object; we can set the queue on this,
       * and the wl_buffer inherits it race-free. */
      params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
      if (dri2_surf)
         wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);

      for (i = 0; i < num_planes; i++) {
         __DRIimage *p_image;
967
968
         int stride, offset;
         int fd = -1;
969

970
         p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
971
         if (!p_image) {
972
973
            assert(i == 0);
            p_image = image;
974
975
         }

976
977
978
979
980
981
982
983
984
         query = dri2_dpy->image->queryImage(p_image,
                                             __DRI_IMAGE_ATTRIB_FD,
                                             &fd);
         query &= dri2_dpy->image->queryImage(p_image,
                                              __DRI_IMAGE_ATTRIB_STRIDE,
                                              &stride);
         query &= dri2_dpy->image->queryImage(p_image,
                                              __DRI_IMAGE_ATTRIB_OFFSET,
                                              &offset);
985
986
987
         if (image != p_image)
            dri2_dpy->image->destroyImage(p_image);

988
989
990
991
992
993
994
         if (!query) {
            if (fd >= 0)
               close(fd);
            zwp_linux_buffer_params_v1_destroy(params);
            return NULL;
         }

995
         zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
996
                                        modifier >> 32, modifier & 0xffffffff);
997
998
         close(fd);
      }
999

1000
1001
1002
1003
      ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
                                                    fourcc, 0);
      zwp_linux_buffer_params_v1_destroy(params);
   } else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
1004
1005
      struct wl_drm *wl_drm =
         dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
1006
1007
      int fd, stride;

1008
1009
1010
      if (num_planes > 1)
         return NULL;

1011
1012
      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
1013
1014
      ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
                                       stride, 0, 0, 0, 0);
1015
1016
      close(fd);
   } else {
1017
1018
      struct wl_drm *wl_drm =
         dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
1019
1020
      int name, stride;

1021
1022
1023
      if (num_planes > 1)
         return NULL;

1024
1025
      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
1026
      ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);
1027
1028
   }

1029
   return ret;
1030
1031
}

1032
1033
1034
1035
1036
static EGLBoolean
try_damage_buffer(struct dri2_egl_surface *dri2_surf,
                  const EGLint *rects,
                  EGLint n_rects)
{
1037
   if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)
1038
1039
1040
       < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
      return EGL_FALSE;

1041
   for (int i = 0; i < n_rects; i++) {
1042
1043
      const int *rect = &rects[i * 4];

1044
      wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,
1045
1046
1047
1048
1049
1050
                               rect[0],
                               dri2_surf->base.Height - rect[1] - rect[3],
                               rect[2], rect[3]);
   }
   return EGL_TRUE;
}
1051

1052
/**
1053
 * Called via eglSwapBuffers(), drv->SwapBuffers().
1054
1055
 */
static EGLBoolean
1056
1057
1058
1059
1060
dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
                                 _EGLDisplay *disp,
                                 _EGLSurface *draw,
                                 const EGLint *rects,
                                 EGLint n_rects)
1061
1062
1063
1064
{
   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);

1065
1066
   while (dri2_surf->throttle_callback != NULL)
      if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
1067
                                    dri2_surf->wl_queue) == -1)
1068
1069
         return -1;

1070
   for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
1071
1072
1073
      if (dri2_surf->color_buffers[i].age > 0)
         dri2_surf->color_buffers[i].age++;

1074
1075
   /* Make sure we have a back buffer in case we're swapping without ever
    * rendering. */
1076
   if (update_buffers_if_needed(dri2_surf) < 0)
1077
      return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
1078

1079
1080
   if (draw->SwapInterval > 0) {
      dri2_surf->throttle_callback =
1081
         wl_surface_frame(dri2_surf->wl_surface_wrapper);
1082
1083
1084
      wl_callback_add_listener(dri2_surf->throttle_callback,
                               &throttle_listener, dri2_surf);
   }
1085

1086
   dri2_surf->back->age = 1;
1087
1088
1089
   dri2_surf->current = dri2_surf->back;
   dri2_surf->back = NULL;

1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
   if (!dri2_surf->current->wl_buffer) {
      __DRIimage *image;

      if (dri2_dpy->is_different_gpu)
         image = dri2_surf->current->linear_copy;
      else
         image = dri2_surf->current->dri_image;

      dri2_surf->current->wl_buffer =
         create_wl_buffer(dri2_dpy, dri2_surf, image);

1101
1102
      dri2_surf->current->wl_release = false;

1103
1104
1105
      wl_buffer_add_listener(dri2_surf->current->wl_buffer,
                             &wl_buffer_listener, dri2_surf);
   }
1106

1107
   wl_surface_attach(dri2_surf->wl_surface_wrapper,
1108
1109
                     dri2_surf->current->wl_buffer,
                     dri2_surf->dx, dri2_surf->dy);
1110

1111
1112
1113
1114
1115
   dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
   dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
   /* reset resize growing parameters */
   dri2_surf->dx = 0;
   dri2_surf->dy = 0;
1116

1117
1118
   /* If the compositor doesn't support damage_buffer, we deliberately
    * ignore the damage region and post maximum damage, due to
1119
    * https://bugs.freedesktop.org/78190 */
1120
   if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
1121
      wl_surface_damage(dri2_surf->wl_surface_wrapper,
1122
                        0, 0, INT32_MAX, INT32_MAX);