OSDN Git Service

egl/wayland: properly destroy wayland objects
[android-x86/external-mesa.git] / src / egl / drivers / dri2 / platform_wayland.c
1 /*
2  * Copyright © 2011-2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Kristian Høgsberg <krh@bitplanet.net>
26  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
27  */
28
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <dlfcn.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <xf86drm.h>
38
39 #include "egl_dri2.h"
40 #include "egl_dri2_fallbacks.h"
41 #include "loader.h"
42
43 #include <wayland-client.h>
44 #include "wayland-drm-client-protocol.h"
45
46 enum wl_drm_format_flags {
47    HAS_ARGB8888 = 1,
48    HAS_XRGB8888 = 2,
49    HAS_RGB565 = 4,
50 };
51
52 static EGLBoolean
53 dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
54                       EGLint interval);
55
56 static void
57 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
58 {
59    int *done = data;
60
61    *done = 1;
62    wl_callback_destroy(callback);
63 }
64
65 static const struct wl_callback_listener sync_listener = {
66    sync_callback
67 };
68
69 static int
70 roundtrip(struct dri2_egl_display *dri2_dpy)
71 {
72    struct wl_callback *callback;
73    int done = 0, ret = 0;
74
75    callback = wl_display_sync(dri2_dpy->wl_dpy);
76    wl_callback_add_listener(callback, &sync_listener, &done);
77    wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue);
78    while (ret != -1 && !done)
79       ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
80
81    if (!done)
82       wl_callback_destroy(callback);
83
84    return ret;
85 }
86
87 static void
88 wl_buffer_release(void *data, struct wl_buffer *buffer)
89 {
90    struct dri2_egl_surface *dri2_surf = data;
91    int i;
92
93    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
94       if (dri2_surf->color_buffers[i].wl_buffer == buffer)
95          break;
96
97    if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
98       wl_buffer_destroy(buffer);
99       return;
100    }
101
102    dri2_surf->color_buffers[i].locked = 0;
103 }
104
105 static struct wl_buffer_listener wl_buffer_listener = {
106    wl_buffer_release
107 };
108
109 static void
110 resize_callback(struct wl_egl_window *wl_win, void *data)
111 {
112    struct dri2_egl_surface *dri2_surf = data;
113    struct dri2_egl_display *dri2_dpy =
114       dri2_egl_display(dri2_surf->base.Resource.Display);
115
116    (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
117 }
118
119 /**
120  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
121  */
122 static _EGLSurface *
123 dri2_wl_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
124                        _EGLConfig *conf, void *native_window,
125                        const EGLint *attrib_list)
126 {
127    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
128    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
129    struct wl_egl_window *window = native_window;
130    struct dri2_egl_surface *dri2_surf;
131
132    (void) drv;
133
134    dri2_surf = calloc(1, sizeof *dri2_surf);
135    if (!dri2_surf) {
136       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
137       return NULL;
138    }
139    
140    if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
141       goto cleanup_surf;
142
143    if (conf->RedSize == 5)
144       dri2_surf->format = WL_DRM_FORMAT_RGB565;
145    else if (conf->AlphaSize == 0)
146       dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
147    else
148       dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
149
150    switch (type) {
151    case EGL_WINDOW_BIT:
152       dri2_surf->wl_win = window;
153
154       dri2_surf->wl_win->private = dri2_surf;
155       dri2_surf->wl_win->resize_callback = resize_callback;
156
157       dri2_surf->base.Width =  -1;
158       dri2_surf->base.Height = -1;
159       break;
160    default: 
161       goto cleanup_surf;
162    }
163
164    dri2_surf->dri_drawable = 
165       (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
166                                             type == EGL_WINDOW_BIT ?
167                                             dri2_conf->dri_double_config : 
168                                             dri2_conf->dri_single_config,
169                                             dri2_surf);
170    if (dri2_surf->dri_drawable == NULL) {
171       _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
172       goto cleanup_dri_drawable;
173    }
174
175    return &dri2_surf->base;
176
177  cleanup_dri_drawable:
178    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
179  cleanup_surf:
180    free(dri2_surf);
181
182    return NULL;
183 }
184
185 /**
186  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
187  */
188 static _EGLSurface *
189 dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
190                               _EGLConfig *conf, void *native_window,
191                               const EGLint *attrib_list)
192 {
193    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
194    _EGLSurface *surf;
195
196    surf = dri2_wl_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
197                                  native_window, attrib_list);
198
199    if (surf != NULL)
200       dri2_wl_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
201
202    return surf;
203 }
204
205 static _EGLSurface *
206 dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
207                               _EGLConfig *conf, void *native_window,
208                               const EGLint *attrib_list)
209 {
210    /* From the EGL_EXT_platform_wayland spec, version 3:
211     *
212     *   It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
213     *   that belongs to Wayland. Any such call fails and generates
214     *   EGL_BAD_PARAMETER.
215     */
216    _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
217              "Wayland");
218    return NULL;
219 }
220
221 /**
222  * Called via eglDestroySurface(), drv->API.DestroySurface().
223  */
224 static EGLBoolean
225 dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
226 {
227    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
228    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
229    int i;
230
231    (void) drv;
232
233    if (!_eglPutSurface(surf))
234       return EGL_TRUE;
235
236    (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
237
238    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
239       if (dri2_surf->color_buffers[i].wl_buffer)
240          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
241       if (dri2_surf->color_buffers[i].dri_image)
242          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
243    }
244
245    for (i = 0; i < __DRI_BUFFER_COUNT; i++)
246       if (dri2_surf->dri_buffers[i] &&
247           dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
248          dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
249                                        dri2_surf->dri_buffers[i]);
250
251    if (dri2_surf->throttle_callback)
252       wl_callback_destroy(dri2_surf->throttle_callback);
253
254    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
255       dri2_surf->wl_win->private = NULL;
256       dri2_surf->wl_win->resize_callback = NULL;
257    }
258
259    free(surf);
260
261    return EGL_TRUE;
262 }
263
264 static void
265 dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
266 {
267    struct dri2_egl_display *dri2_dpy =
268       dri2_egl_display(dri2_surf->base.Resource.Display);
269    int i;
270
271    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
272       if (dri2_surf->color_buffers[i].wl_buffer &&
273           !dri2_surf->color_buffers[i].locked)
274          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
275       if (dri2_surf->color_buffers[i].dri_image)
276          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
277
278       dri2_surf->color_buffers[i].wl_buffer = NULL;
279       dri2_surf->color_buffers[i].dri_image = NULL;
280       dri2_surf->color_buffers[i].locked = 0;
281    }
282
283    for (i = 0; i < __DRI_BUFFER_COUNT; i++)
284       if (dri2_surf->dri_buffers[i] &&
285           dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
286          dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
287                                        dri2_surf->dri_buffers[i]);
288 }
289
290 static int
291 get_back_bo(struct dri2_egl_surface *dri2_surf)
292 {
293    struct dri2_egl_display *dri2_dpy =
294       dri2_egl_display(dri2_surf->base.Resource.Display);
295    int i;
296    unsigned int dri_image_format;
297
298    /* currently supports three WL DRM formats,
299     * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
300     * and WL_DRM_FORMAT_RGB565
301     */
302    switch (dri2_surf->format) {
303    case WL_DRM_FORMAT_ARGB8888:
304       dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
305       break;
306    case WL_DRM_FORMAT_XRGB8888:
307       dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
308       break;
309    case WL_DRM_FORMAT_RGB565:
310       dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
311       break;
312    default:
313       /* format is not supported */
314       return -1;
315    }
316
317    /* We always want to throttle to some event (either a frame callback or
318     * a sync request) after the commit so that we can be sure the
319     * compositor has had a chance to handle it and send us a release event
320     * before we look for a free buffer */
321    while (dri2_surf->throttle_callback != NULL)
322       if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
323                                     dri2_dpy->wl_queue) == -1)
324          return -1;
325
326    if (dri2_surf->back == NULL) {
327       for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
328          /* Get an unlocked buffer, preferrably one with a dri_buffer
329           * already allocated. */
330          if (dri2_surf->color_buffers[i].locked)
331             continue;
332          if (dri2_surf->back == NULL)
333             dri2_surf->back = &dri2_surf->color_buffers[i];
334          else if (dri2_surf->back->dri_image == NULL)
335             dri2_surf->back = &dri2_surf->color_buffers[i];
336       }
337    }
338
339    if (dri2_surf->back == NULL)
340       return -1;
341    if (dri2_surf->back->dri_image == NULL) {
342       dri2_surf->back->dri_image = 
343          dri2_dpy->image->createImage(dri2_dpy->dri_screen,
344                                       dri2_surf->base.Width,
345                                       dri2_surf->base.Height,
346                                       dri_image_format,
347                                       __DRI_IMAGE_USE_SHARE,
348                                       NULL);
349       dri2_surf->back->age = 0;
350    }
351    if (dri2_surf->back->dri_image == NULL)
352       return -1;
353
354    dri2_surf->back->locked = 1;
355
356    return 0;
357 }
358
359
360 static void
361 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
362 {
363    struct dri2_egl_display *dri2_dpy =
364       dri2_egl_display(dri2_surf->base.Resource.Display);
365    __DRIimage *image;
366    int name, pitch;
367
368    image = dri2_surf->back->dri_image;
369
370    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
371    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
372
373    buffer->attachment = __DRI_BUFFER_BACK_LEFT;
374    buffer->name = name;
375    buffer->pitch = pitch;
376    buffer->cpp = 4;
377    buffer->flags = 0;
378 }
379
380 static int
381 get_aux_bo(struct dri2_egl_surface *dri2_surf,
382            unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
383 {
384    struct dri2_egl_display *dri2_dpy =
385       dri2_egl_display(dri2_surf->base.Resource.Display);
386    __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
387
388    if (b == NULL) {
389       b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
390                                          attachment, format,
391                                          dri2_surf->base.Width,
392                                          dri2_surf->base.Height);
393       dri2_surf->dri_buffers[attachment] = b;
394    }
395    if (b == NULL)
396       return -1;
397
398    memcpy(buffer, b, sizeof *buffer);
399
400    return 0;
401 }
402
403 static int
404 update_buffers(struct dri2_egl_surface *dri2_surf)
405 {
406    struct dri2_egl_display *dri2_dpy =
407       dri2_egl_display(dri2_surf->base.Resource.Display);
408    int i;
409
410    if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
411        (dri2_surf->base.Width != dri2_surf->wl_win->width || 
412         dri2_surf->base.Height != dri2_surf->wl_win->height)) {
413
414       dri2_wl_release_buffers(dri2_surf);
415
416       dri2_surf->base.Width  = dri2_surf->wl_win->width;
417       dri2_surf->base.Height = dri2_surf->wl_win->height;
418       dri2_surf->dx = dri2_surf->wl_win->dx;
419       dri2_surf->dy = dri2_surf->wl_win->dy;
420    }
421
422    if (get_back_bo(dri2_surf) < 0) {
423       _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
424       return -1;
425    }
426
427    /* If we have an extra unlocked buffer at this point, we had to do triple
428     * buffering for a while, but now can go back to just double buffering.
429     * That means we can free any unlocked buffer now. */
430    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
431       if (!dri2_surf->color_buffers[i].locked &&
432           dri2_surf->color_buffers[i].wl_buffer) {
433          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
434          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
435          dri2_surf->color_buffers[i].wl_buffer = NULL;
436          dri2_surf->color_buffers[i].dri_image = NULL;
437       }
438    }
439
440    return 0;
441 }
442
443 static __DRIbuffer *
444 dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
445                                 int *width, int *height,
446                                 unsigned int *attachments, int count,
447                                 int *out_count, void *loaderPrivate)
448 {
449    struct dri2_egl_surface *dri2_surf = loaderPrivate;
450    int i, j;
451
452    if (update_buffers(dri2_surf) < 0)
453       return NULL;
454
455    for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
456       switch (attachments[i]) {
457       case __DRI_BUFFER_BACK_LEFT:
458          back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
459          break;
460       default:
461          if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
462                         &dri2_surf->buffers[j]) < 0) {
463             _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
464             return NULL;
465          }
466          break;
467       }
468    }
469
470    *out_count = j;
471    if (j == 0)
472            return NULL;
473
474    *width = dri2_surf->base.Width;
475    *height = dri2_surf->base.Height;
476
477    return dri2_surf->buffers;
478 }
479
480 static __DRIbuffer *
481 dri2_wl_get_buffers(__DRIdrawable * driDrawable,
482                     int *width, int *height,
483                     unsigned int *attachments, int count,
484                     int *out_count, void *loaderPrivate)
485 {
486    struct dri2_egl_surface *dri2_surf = loaderPrivate;
487    unsigned int *attachments_with_format;
488    __DRIbuffer *buffer;
489    unsigned int bpp;
490
491    int i;
492
493    switch (dri2_surf->format) {
494    case WL_DRM_FORMAT_ARGB8888:
495    case WL_DRM_FORMAT_XRGB8888:
496       bpp = 32;
497       break;
498    case WL_DRM_FORMAT_RGB565:
499       bpp = 16;
500       break;
501    default:
502       /* format is not supported */
503       return NULL;
504    }
505
506    attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
507    if (!attachments_with_format) {
508       *out_count = 0;
509       return NULL;
510    }
511
512    for (i = 0; i < count; ++i) {
513       attachments_with_format[2*i] = attachments[i];
514       attachments_with_format[2*i + 1] = bpp;
515    }
516
517    buffer =
518       dri2_wl_get_buffers_with_format(driDrawable,
519                                       width, height,
520                                       attachments_with_format, count,
521                                       out_count, loaderPrivate);
522
523    free(attachments_with_format);
524
525    return buffer;
526 }
527
528 static int
529 image_get_buffers(__DRIdrawable *driDrawable,
530                   unsigned int format,
531                   uint32_t *stamp,
532                   void *loaderPrivate,
533                   uint32_t buffer_mask,
534                   struct __DRIimageList *buffers)
535 {
536    struct dri2_egl_surface *dri2_surf = loaderPrivate;
537
538    if (update_buffers(dri2_surf) < 0)
539       return 0;
540
541    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
542    buffers->back = dri2_surf->back->dri_image;
543
544    return 1;
545 }
546
547 static void
548 dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
549 {
550    (void) driDrawable;
551    (void) loaderPrivate;
552 }
553
554 static const __DRIimageLoaderExtension image_loader_extension = {
555    .base = { __DRI_IMAGE_LOADER, 1 },
556
557    .getBuffers          = image_get_buffers,
558    .flushFrontBuffer    = dri2_wl_flush_front_buffer,
559 };
560
561 static void
562 wayland_throttle_callback(void *data,
563                           struct wl_callback *callback,
564                           uint32_t time)
565 {
566    struct dri2_egl_surface *dri2_surf = data;
567
568    dri2_surf->throttle_callback = NULL;
569    wl_callback_destroy(callback);
570 }
571
572 static const struct wl_callback_listener throttle_listener = {
573    wayland_throttle_callback
574 };
575
576 static void
577 create_wl_buffer(struct dri2_egl_surface *dri2_surf)
578 {
579    struct dri2_egl_display *dri2_dpy =
580       dri2_egl_display(dri2_surf->base.Resource.Display);
581    int fd, stride, name;
582
583    if (dri2_surf->current->wl_buffer != NULL)
584       return;
585
586    if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
587       dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
588                                   __DRI_IMAGE_ATTRIB_FD, &fd);
589       dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
590                                   __DRI_IMAGE_ATTRIB_STRIDE, &stride);
591
592       dri2_surf->current->wl_buffer =
593          wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
594                                     fd,
595                                     dri2_surf->base.Width,
596                                     dri2_surf->base.Height,
597                                     dri2_surf->format,
598                                     0, stride,
599                                     0, 0,
600                                     0, 0);
601       close(fd);
602    } else {
603       dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
604                                   __DRI_IMAGE_ATTRIB_NAME, &name);
605       dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
606                                   __DRI_IMAGE_ATTRIB_STRIDE, &stride);
607
608       dri2_surf->current->wl_buffer =
609          wl_drm_create_buffer(dri2_dpy->wl_drm,
610                               name,
611                               dri2_surf->base.Width,
612                               dri2_surf->base.Height,
613                               stride,
614                               dri2_surf->format);
615    }
616
617    wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer,
618                       dri2_dpy->wl_queue);
619    wl_buffer_add_listener(dri2_surf->current->wl_buffer,
620                           &wl_buffer_listener, dri2_surf);
621 }
622
623 /**
624  * Called via eglSwapBuffers(), drv->API.SwapBuffers().
625  */
626 static EGLBoolean
627 dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
628                                  _EGLDisplay *disp,
629                                  _EGLSurface *draw,
630                                  const EGLint *rects,
631                                  EGLint n_rects)
632 {
633    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
634    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
635    int i;
636
637    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
638       if (dri2_surf->color_buffers[i].age > 0)
639          dri2_surf->color_buffers[i].age++;
640
641    /* Make sure we have a back buffer in case we're swapping without ever
642     * rendering. */
643    if (get_back_bo(dri2_surf) < 0) {
644       _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
645       return EGL_FALSE;
646    }
647
648    if (draw->SwapInterval > 0) {
649       dri2_surf->throttle_callback =
650          wl_surface_frame(dri2_surf->wl_win->surface);
651       wl_callback_add_listener(dri2_surf->throttle_callback,
652                                &throttle_listener, dri2_surf);
653       wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
654                          dri2_dpy->wl_queue);
655    }
656
657    dri2_surf->back->age = 1;
658    dri2_surf->current = dri2_surf->back;
659    dri2_surf->back = NULL;
660
661    create_wl_buffer(dri2_surf);
662
663    wl_surface_attach(dri2_surf->wl_win->surface,
664                      dri2_surf->current->wl_buffer,
665                      dri2_surf->dx, dri2_surf->dy);
666
667    dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
668    dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
669    /* reset resize growing parameters */
670    dri2_surf->dx = 0;
671    dri2_surf->dy = 0;
672
673    if (n_rects == 0) {
674       wl_surface_damage(dri2_surf->wl_win->surface,
675                         0, 0, INT32_MAX, INT32_MAX);
676    } else {
677       for (i = 0; i < n_rects; i++) {
678          const int *rect = &rects[i * 4];
679          wl_surface_damage(dri2_surf->wl_win->surface,
680                            rect[0],
681                            dri2_surf->base.Height - rect[1] - rect[3],
682                            rect[2], rect[3]);
683       }
684    }
685
686    dri2_flush_drawable_for_swapbuffers(disp, draw);
687    (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
688
689    wl_surface_commit(dri2_surf->wl_win->surface);
690
691    /* If we're not waiting for a frame callback then we'll at least throttle
692     * to a sync callback so that we always give a chance for the compositor to
693     * handle the commit and send a release event before checking for a free
694     * buffer */
695    if (dri2_surf->throttle_callback == NULL) {
696       dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
697       wl_callback_add_listener(dri2_surf->throttle_callback,
698                                &throttle_listener, dri2_surf);
699       wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
700                          dri2_dpy->wl_queue);
701    }
702
703    wl_display_flush(dri2_dpy->wl_dpy);
704
705    return EGL_TRUE;
706 }
707
708 static EGLint
709 dri2_wl_query_buffer_age(_EGLDriver *drv,
710                          _EGLDisplay *disp, _EGLSurface *surface)
711 {
712    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
713
714    if (get_back_bo(dri2_surf) < 0) {
715       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
716       return 0;
717    }
718
719    return dri2_surf->back->age;
720 }
721
722 static EGLBoolean
723 dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
724 {
725    return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
726 }
727
728 static struct wl_buffer *
729 dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
730                                           _EGLDisplay *disp,
731                                           _EGLImage *img)
732 {
733    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
734    struct dri2_egl_image *dri2_img = dri2_egl_image(img);
735    __DRIimage *image = dri2_img->dri_image;
736    struct wl_buffer *buffer;
737    int width, height, format, pitch;
738    enum wl_drm_format wl_format;
739
740    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
741
742    switch (format) {
743    case __DRI_IMAGE_FORMAT_ARGB8888:
744       if (!(dri2_dpy->formats & HAS_ARGB8888))
745          goto bad_format;
746       wl_format = WL_DRM_FORMAT_ARGB8888;
747       break;
748    case __DRI_IMAGE_FORMAT_XRGB8888:
749       if (!(dri2_dpy->formats & HAS_XRGB8888))
750          goto bad_format;
751       wl_format = WL_DRM_FORMAT_XRGB8888;
752       break;
753    default:
754       goto bad_format;
755    }
756
757    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
758    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
759    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
760
761    if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
762       int fd;
763
764       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
765
766       buffer =
767          wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
768                                     fd,
769                                     width, height,
770                                     wl_format,
771                                     0, pitch,
772                                     0, 0,
773                                     0, 0);
774
775       close(fd);
776    } else {
777       int name;
778
779       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
780
781       buffer =
782          wl_drm_create_buffer(dri2_dpy->wl_drm,
783                               name,
784                               width, height,
785                               pitch,
786                               wl_format);
787    }
788
789    /* The buffer object will have been created with our internal event queue
790     * because it is using the wl_drm object as a proxy factory. We want the
791     * buffer to be used by the application so we'll reset it to the display's
792     * default event queue */
793    if (buffer)
794       wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
795
796    return buffer;
797
798 bad_format:
799    _eglError(EGL_BAD_MATCH, "unsupported image format");
800    return NULL;
801 }
802
803 static int
804 dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
805 {
806    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
807    int ret = 0;
808
809    dri2_dpy->authenticated = 0;
810
811    wl_drm_authenticate(dri2_dpy->wl_drm, id);
812    if (roundtrip(dri2_dpy) < 0)
813       ret = -1;
814
815    if (!dri2_dpy->authenticated)
816       ret = -1;
817
818    /* reset authenticated */
819    dri2_dpy->authenticated = 1;
820
821    return ret;
822 }
823
824 static void
825 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
826 {
827    struct dri2_egl_display *dri2_dpy = data;
828    drm_magic_t magic;
829
830    dri2_dpy->device_name = strdup(device);
831    if (!dri2_dpy->device_name)
832       return;
833
834 #ifdef O_CLOEXEC
835    dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
836    if (dri2_dpy->fd == -1 && errno == EINVAL)
837 #endif
838    {
839       dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
840       if (dri2_dpy->fd != -1)
841          fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
842             FD_CLOEXEC);
843    }
844    if (dri2_dpy->fd == -1) {
845       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
846               dri2_dpy->device_name, strerror(errno));
847       return;
848    }
849
850    drmGetMagic(dri2_dpy->fd, &magic);
851    wl_drm_authenticate(dri2_dpy->wl_drm, magic);
852 }
853
854 static void
855 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
856 {
857    struct dri2_egl_display *dri2_dpy = data;
858
859    switch (format) {
860    case WL_DRM_FORMAT_ARGB8888:
861       dri2_dpy->formats |= HAS_ARGB8888;
862       break;
863    case WL_DRM_FORMAT_XRGB8888:
864       dri2_dpy->formats |= HAS_XRGB8888;
865       break;
866    case WL_DRM_FORMAT_RGB565:
867       dri2_dpy->formats |= HAS_RGB565;
868       break;
869    }
870 }
871
872 static void
873 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
874 {
875    struct dri2_egl_display *dri2_dpy = data;
876
877    dri2_dpy->capabilities = value;
878 }
879
880 static void
881 drm_handle_authenticated(void *data, struct wl_drm *drm)
882 {
883    struct dri2_egl_display *dri2_dpy = data;
884
885    dri2_dpy->authenticated = 1;
886 }
887
888 static const struct wl_drm_listener drm_listener = {
889         drm_handle_device,
890         drm_handle_format,
891         drm_handle_authenticated,
892         drm_handle_capabilities
893 };
894
895 static void
896 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
897                        const char *interface, uint32_t version)
898 {
899    struct dri2_egl_display *dri2_dpy = data;
900
901    if (version > 1)
902       version = 2;
903    if (strcmp(interface, "wl_drm") == 0) {
904       dri2_dpy->wl_drm =
905          wl_registry_bind(registry, name, &wl_drm_interface, version);
906       wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
907    }
908 }
909
910 static void
911 registry_handle_global_remove(void *data, struct wl_registry *registry,
912                               uint32_t name)
913 {
914 }
915
916 static const struct wl_registry_listener registry_listener = {
917    registry_handle_global,
918    registry_handle_global_remove
919 };
920
921 static EGLBoolean
922 dri2_wl_swap_interval(_EGLDriver *drv,
923                    _EGLDisplay *disp,
924                    _EGLSurface *surf,
925                    EGLint interval)
926 {
927    if (interval > surf->Config->MaxSwapInterval)
928       interval = surf->Config->MaxSwapInterval;
929    else if (interval < surf->Config->MinSwapInterval)
930       interval = surf->Config->MinSwapInterval;
931
932    surf->SwapInterval = interval;
933
934    return EGL_TRUE;
935 }
936
937 static void
938 dri2_wl_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
939 {
940    GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
941
942    /* We can't use values greater than 1 on Wayland because we are using the
943     * frame callback to synchronise the frame and the only way we be sure to
944     * get a frame callback is to attach a new buffer. Therefore we can't just
945     * sit drawing nothing to wait until the next ‘n’ frame callbacks */
946
947    if (dri2_dpy->config)
948       dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
949                                      "vblank_mode", &vblank_mode);
950    switch (vblank_mode) {
951    case DRI_CONF_VBLANK_NEVER:
952       dri2_dpy->min_swap_interval = 0;
953       dri2_dpy->max_swap_interval = 0;
954       dri2_dpy->default_swap_interval = 0;
955       break;
956    case DRI_CONF_VBLANK_ALWAYS_SYNC:
957       dri2_dpy->min_swap_interval = 1;
958       dri2_dpy->max_swap_interval = 1;
959       dri2_dpy->default_swap_interval = 1;
960       break;
961    case DRI_CONF_VBLANK_DEF_INTERVAL_0:
962       dri2_dpy->min_swap_interval = 0;
963       dri2_dpy->max_swap_interval = 1;
964       dri2_dpy->default_swap_interval = 0;
965       break;
966    default:
967    case DRI_CONF_VBLANK_DEF_INTERVAL_1:
968       dri2_dpy->min_swap_interval = 0;
969       dri2_dpy->max_swap_interval = 1;
970       dri2_dpy->default_swap_interval = 1;
971       break;
972    }
973 }
974
975 static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
976    .authenticate = dri2_wl_authenticate,
977    .create_window_surface = dri2_wl_create_window_surface,
978    .create_pixmap_surface = dri2_wl_create_pixmap_surface,
979    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
980    .destroy_surface = dri2_wl_destroy_surface,
981    .create_image = dri2_create_image_khr,
982    .swap_interval = dri2_wl_swap_interval,
983    .swap_buffers = dri2_wl_swap_buffers,
984    .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
985    .swap_buffers_region = dri2_fallback_swap_buffers_region,
986    .post_sub_buffer = dri2_fallback_post_sub_buffer,
987    .copy_buffers = dri2_fallback_copy_buffers,
988    .query_buffer_age = dri2_wl_query_buffer_age,
989    .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
990    .get_sync_values = dri2_fallback_get_sync_values,
991 };
992
993 EGLBoolean
994 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
995 {
996    struct dri2_egl_display *dri2_dpy;
997    const __DRIconfig *config;
998    uint32_t types;
999    int i;
1000    static const unsigned int argb_masks[4] =
1001       { 0xff0000, 0xff00, 0xff, 0xff000000 };
1002    static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
1003    static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 };
1004
1005    loader_set_logger(_eglLog);
1006
1007    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1008    if (!dri2_dpy)
1009       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1010
1011    disp->DriverData = (void *) dri2_dpy;
1012    if (disp->PlatformDisplay == NULL) {
1013       dri2_dpy->wl_dpy = wl_display_connect(NULL);
1014       if (dri2_dpy->wl_dpy == NULL)
1015          goto cleanup_dpy;
1016       dri2_dpy->own_device = 1;
1017    } else {
1018       dri2_dpy->wl_dpy = disp->PlatformDisplay;
1019    }
1020
1021    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
1022
1023    if (dri2_dpy->own_device)
1024       wl_display_dispatch_pending(dri2_dpy->wl_dpy);
1025
1026    dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
1027    wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
1028                       dri2_dpy->wl_queue);
1029    wl_registry_add_listener(dri2_dpy->wl_registry,
1030                             &registry_listener, dri2_dpy);
1031    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
1032       goto cleanup_registry;
1033
1034    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
1035       goto cleanup_drm;
1036
1037    if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
1038       goto cleanup_fd;
1039
1040    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
1041    if (dri2_dpy->driver_name == NULL) {
1042       _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
1043       goto cleanup_fd;
1044    }
1045
1046    if (!dri2_load_driver(disp))
1047       goto cleanup_driver_name;
1048
1049    dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1050    dri2_dpy->dri2_loader_extension.base.version = 3;
1051    dri2_dpy->dri2_loader_extension.getBuffers = dri2_wl_get_buffers;
1052    dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_wl_flush_front_buffer;
1053    dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
1054       dri2_wl_get_buffers_with_format;
1055
1056    dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
1057    dri2_dpy->extensions[1] = &image_loader_extension.base;
1058    dri2_dpy->extensions[2] = &image_lookup_extension.base;
1059    dri2_dpy->extensions[3] = &use_invalidate.base;
1060    dri2_dpy->extensions[4] = NULL;
1061
1062    dri2_dpy->swap_available = EGL_TRUE;
1063
1064    if (!dri2_create_screen(disp))
1065       goto cleanup_driver;
1066
1067    dri2_wl_setup_swap_interval(dri2_dpy);
1068
1069    /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver
1070     * doesn't have createImageFromFds, since we're using the same driver on
1071     * both sides.  We don't want crash if that happens anyway, so fall back to
1072     * gem names if we don't have prime support. */
1073
1074    if (dri2_dpy->image->base.version < 7 ||
1075        dri2_dpy->image->createImageFromFds == NULL)
1076       dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
1077
1078    types = EGL_WINDOW_BIT;
1079    for (i = 0; dri2_dpy->driver_configs[i]; i++) {
1080       config = dri2_dpy->driver_configs[i];
1081       if (dri2_dpy->formats & HAS_XRGB8888)
1082          dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks);
1083       if (dri2_dpy->formats & HAS_ARGB8888)
1084          dri2_add_config(disp, config, i + 1, types, NULL, argb_masks);
1085       if (dri2_dpy->formats & HAS_RGB565)
1086         dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks);
1087    }
1088
1089    disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1090    disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
1091    disp->Extensions.EXT_buffer_age = EGL_TRUE;
1092
1093    disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1094
1095    /* we're supporting EGL 1.4 */
1096    disp->VersionMajor = 1;
1097    disp->VersionMinor = 4;
1098
1099    /* Fill vtbl last to prevent accidentally calling virtual function during
1100     * initialization.
1101     */
1102    dri2_dpy->vtbl = &dri2_wl_display_vtbl;
1103
1104    return EGL_TRUE;
1105
1106  cleanup_driver:
1107    dlclose(dri2_dpy->driver);
1108  cleanup_driver_name:
1109    free(dri2_dpy->driver_name);
1110  cleanup_fd:
1111    close(dri2_dpy->fd);
1112  cleanup_drm:
1113    free(dri2_dpy->device_name);
1114    wl_drm_destroy(dri2_dpy->wl_drm);
1115  cleanup_registry:
1116    wl_registry_destroy(dri2_dpy->wl_registry);
1117    wl_event_queue_destroy(dri2_dpy->wl_queue);
1118  cleanup_dpy:
1119    free(dri2_dpy);
1120    
1121    return EGL_FALSE;
1122 }