platform_wayland.c revision a5776ac0b8c015bf5d6a8513cefec5920895cc8e
1/*
2 * Copyright © 2011 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 <stdlib.h>
30#include <string.h>
31#include <limits.h>
32#include <dlfcn.h>
33#include <errno.h>
34#include <unistd.h>
35#include <fcntl.h>
36#include <xf86drm.h>
37
38#include "egl_dri2.h"
39
40#include <wayland-client.h>
41#include "wayland-drm-client-protocol.h"
42
43enum wl_drm_format_flags {
44   HAS_ARGB8888 = 1,
45   HAS_XRGB8888 = 2
46};
47
48static void
49sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
50{
51   int *done = data;
52
53   *done = 1;
54   wl_callback_destroy(callback);
55}
56
57static const struct wl_callback_listener sync_listener = {
58   sync_callback
59};
60
61static int
62roundtrip(struct dri2_egl_display *dri2_dpy)
63{
64   struct wl_callback *callback;
65   int done = 0, ret = 0;
66
67   callback = wl_display_sync(dri2_dpy->wl_dpy);
68   wl_callback_add_listener(callback, &sync_listener, &done);
69   wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue);
70   while (ret != -1 && !done)
71      ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
72
73   return ret;
74}
75
76static void
77wl_buffer_release(void *data, struct wl_buffer *buffer)
78{
79   struct dri2_egl_surface *dri2_surf = data;
80   int i;
81
82   for (i = 0; i < WL_BUFFER_COUNT; ++i)
83      if (dri2_surf->wl_drm_buffer[i] == buffer)
84         break;
85
86   assert(i <= WL_BUFFER_COUNT);
87
88   /* not found? */
89   if (i == WL_BUFFER_COUNT)
90      return;
91
92   dri2_surf->wl_buffer_lock[i] = 0;
93
94}
95
96static struct wl_buffer_listener wl_buffer_listener = {
97   wl_buffer_release
98};
99
100/**
101 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
102 */
103static _EGLSurface *
104dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
105		    _EGLConfig *conf, EGLNativeWindowType window,
106		    const EGLint *attrib_list)
107{
108   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
109   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
110   struct dri2_egl_surface *dri2_surf;
111   struct dri2_egl_buffer *dri2_buf;
112   int i;
113
114   (void) drv;
115
116   dri2_surf = malloc(sizeof *dri2_surf);
117   if (!dri2_surf) {
118      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
119      return NULL;
120   }
121
122   if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
123      goto cleanup_surf;
124
125   for (i = 0; i < WL_BUFFER_COUNT; ++i) {
126      dri2_surf->wl_drm_buffer[i] = NULL;
127      dri2_surf->wl_buffer_lock[i] = 0;
128   }
129
130   for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
131      dri2_surf->dri_buffers[i] = NULL;
132
133   dri2_surf->pending_buffer = NULL;
134   dri2_surf->third_buffer = NULL;
135   dri2_surf->frame_callback = NULL;
136
137   if (conf->AlphaSize == 0)
138      dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
139   else
140      dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
141
142   switch (type) {
143   case EGL_WINDOW_BIT:
144      dri2_surf->wl_win = (struct wl_egl_window *) window;
145
146      dri2_surf->base.Width =  -1;
147      dri2_surf->base.Height = -1;
148      break;
149   case EGL_PIXMAP_BIT:
150      dri2_surf->wl_pix = (struct wl_egl_pixmap *) window;
151
152      dri2_surf->base.Width  = dri2_surf->wl_pix->width;
153      dri2_surf->base.Height = dri2_surf->wl_pix->height;
154
155      if (dri2_surf->wl_pix->driver_private) {
156         dri2_buf = dri2_surf->wl_pix->driver_private;
157         dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = dri2_buf->dri_buffer;
158      }
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 */
188static _EGLSurface *
189dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
190			   _EGLConfig *conf, EGLNativeWindowType window,
191			   const EGLint *attrib_list)
192{
193   return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
194			      window, attrib_list);
195}
196
197static _EGLSurface *
198dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
199			   _EGLConfig *conf, EGLNativePixmapType pixmap,
200			   const EGLint *attrib_list)
201{
202   return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
203			      pixmap, attrib_list);
204}
205
206/**
207 * Called via eglDestroySurface(), drv->API.DestroySurface().
208 */
209static EGLBoolean
210dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
211{
212   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
213   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
214   int i;
215
216   (void) drv;
217
218   if (!_eglPutSurface(surf))
219      return EGL_TRUE;
220
221   (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
222
223   for (i = 0; i < WL_BUFFER_COUNT; ++i)
224      if (dri2_surf->wl_drm_buffer[i])
225         wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
226
227   for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
228      if (dri2_surf->dri_buffers[i] && !(i == __DRI_BUFFER_FRONT_LEFT &&
229          dri2_surf->base.Type == EGL_PIXMAP_BIT))
230         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
231                                       dri2_surf->dri_buffers[i]);
232
233   if (dri2_surf->third_buffer) {
234      dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
235                                    dri2_surf->third_buffer);
236   }
237
238   free(surf);
239
240   return EGL_TRUE;
241}
242
243static void
244dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
245{
246   struct dri2_egl_buffer *dri2_buf = egl_pixmap->driver_private;
247
248   assert(dri2_buf);
249
250   dri2_buf->dri2_dpy->dri2->releaseBuffer(dri2_buf->dri2_dpy->dri_screen,
251                                           dri2_buf->dri_buffer);
252
253   free(dri2_buf);
254
255   egl_pixmap->driver_private = NULL;
256   egl_pixmap->destroy = NULL;
257}
258
259static struct wl_buffer *
260wayland_create_buffer(struct dri2_egl_surface *dri2_surf,
261                      __DRIbuffer *buffer)
262{
263   struct dri2_egl_display *dri2_dpy =
264      dri2_egl_display(dri2_surf->base.Resource.Display);
265   struct wl_buffer *buf;
266
267   buf = wl_drm_create_buffer(dri2_dpy->wl_drm, buffer->name,
268                              dri2_surf->base.Width, dri2_surf->base.Height,
269                              buffer->pitch, dri2_surf->format);
270   wl_buffer_add_listener(buf, &wl_buffer_listener, dri2_surf);
271
272   return buf;
273}
274
275static void
276dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
277{
278   struct dri2_egl_display *dri2_dpy =
279      dri2_egl_display(dri2_surf->base.Resource.Display);
280
281   (void) format;
282
283   switch (dri2_surf->base.Type) {
284   case EGL_WINDOW_BIT:
285      /* allocate a front buffer for our double-buffered window*/
286      if (dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] != NULL)
287         break;
288      dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] =
289         dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
290               __DRI_BUFFER_FRONT_LEFT, format,
291               dri2_surf->base.Width, dri2_surf->base.Height);
292      break;
293   default:
294      break;
295   }
296}
297
298static void
299dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
300{
301   struct dri2_egl_display *dri2_dpy =
302      dri2_egl_display(dri2_surf->base.Resource.Display);
303   struct dri2_egl_buffer *dri2_buf;
304
305   switch (dri2_surf->base.Type) {
306   case EGL_PIXMAP_BIT:
307      dri2_buf = malloc(sizeof *dri2_buf);
308      if (!dri2_buf)
309         return;
310
311      dri2_buf->dri_buffer = dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT];
312      dri2_buf->dri2_dpy   = dri2_dpy;
313
314      dri2_surf->wl_pix->driver_private = dri2_buf;
315      dri2_surf->wl_pix->destroy        = dri2_wl_egl_pixmap_destroy;
316      break;
317   default:
318      break;
319   }
320}
321
322static void
323dri2_release_pending_buffer(void *data,
324			    struct wl_callback *callback, uint32_t time)
325{
326   struct dri2_egl_surface *dri2_surf = data;
327   struct dri2_egl_display *dri2_dpy =
328      dri2_egl_display(dri2_surf->base.Resource.Display);
329
330   /* FIXME: print internal error */
331   if (!dri2_surf->pending_buffer)
332      return;
333
334   dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
335                                 dri2_surf->pending_buffer);
336   dri2_surf->pending_buffer = NULL;
337
338   wl_callback_destroy(callback);
339}
340
341static const struct wl_callback_listener release_buffer_listener = {
342   dri2_release_pending_buffer
343};
344
345static void
346dri2_release_buffers(struct dri2_egl_surface *dri2_surf)
347{
348   struct dri2_egl_display *dri2_dpy =
349      dri2_egl_display(dri2_surf->base.Resource.Display);
350   struct wl_callback *callback;
351   int i;
352
353   if (dri2_surf->third_buffer) {
354      dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
355                                    dri2_surf->third_buffer);
356      dri2_surf->third_buffer = NULL;
357   }
358
359   for (i = 0; i < __DRI_BUFFER_COUNT; ++i) {
360      if (dri2_surf->dri_buffers[i]) {
361         switch (i) {
362         case __DRI_BUFFER_FRONT_LEFT:
363            if (dri2_surf->pending_buffer)
364               roundtrip(dri2_dpy);
365            dri2_surf->pending_buffer = dri2_surf->dri_buffers[i];
366            callback = wl_display_sync(dri2_dpy->wl_dpy);
367	    wl_callback_add_listener(callback,
368				     &release_buffer_listener, dri2_surf);
369            wl_proxy_set_queue((struct wl_proxy *) callback,
370                               dri2_dpy->wl_queue);
371            break;
372         default:
373            dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
374                                          dri2_surf->dri_buffers[i]);
375            break;
376         }
377         dri2_surf->dri_buffers[i] = NULL;
378      }
379   }
380}
381
382static inline void
383pointer_swap(const void **p1, const void **p2)
384{
385   const void *tmp = *p1;
386   *p1 = *p2;
387   *p2 = tmp;
388}
389
390static void
391destroy_third_buffer(struct dri2_egl_surface *dri2_surf)
392{
393   struct dri2_egl_display *dri2_dpy =
394      dri2_egl_display(dri2_surf->base.Resource.Display);
395
396   if (dri2_surf->third_buffer == NULL)
397      return;
398
399   dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
400                                 dri2_surf->third_buffer);
401   dri2_surf->third_buffer = NULL;
402
403   if (dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD])
404      wl_buffer_destroy(dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD]);
405   dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD] = NULL;
406   dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD] = 0;
407}
408
409static void
410swap_wl_buffers(struct dri2_egl_surface *dri2_surf,
411                enum wayland_buffer_type a, enum wayland_buffer_type b)
412{
413   int tmp;
414
415   tmp = dri2_surf->wl_buffer_lock[a];
416   dri2_surf->wl_buffer_lock[a] = dri2_surf->wl_buffer_lock[b];
417   dri2_surf->wl_buffer_lock[b] = tmp;
418
419   pointer_swap((const void **) &dri2_surf->wl_drm_buffer[a],
420                (const void **) &dri2_surf->wl_drm_buffer[b]);
421}
422
423static void
424swap_back_and_third(struct dri2_egl_surface *dri2_surf)
425{
426   if (dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD])
427      destroy_third_buffer(dri2_surf);
428
429   pointer_swap((const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT],
430                (const void **) &dri2_surf->third_buffer);
431
432   swap_wl_buffers(dri2_surf, WL_BUFFER_BACK, WL_BUFFER_THIRD);
433}
434
435static void
436dri2_prior_buffer_creation(struct dri2_egl_surface *dri2_surf,
437                           unsigned int type)
438{
439   switch (type) {
440   case __DRI_BUFFER_BACK_LEFT:
441         if (dri2_surf->wl_buffer_lock[WL_BUFFER_BACK])
442            swap_back_and_third(dri2_surf);
443         else if (dri2_surf->third_buffer)
444            destroy_third_buffer(dri2_surf);
445         break;
446   default:
447         break;
448
449   }
450}
451
452static __DRIbuffer *
453dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
454			     int *width, int *height,
455			     unsigned int *attachments, int count,
456			     int *out_count, void *loaderPrivate)
457{
458   struct dri2_egl_surface *dri2_surf = loaderPrivate;
459   struct dri2_egl_display *dri2_dpy =
460      dri2_egl_display(dri2_surf->base.Resource.Display);
461   int i;
462
463   if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
464       (dri2_surf->base.Width != dri2_surf->wl_win->width ||
465        dri2_surf->base.Height != dri2_surf->wl_win->height)) {
466
467      dri2_release_buffers(dri2_surf);
468
469      dri2_surf->base.Width  = dri2_surf->wl_win->width;
470      dri2_surf->base.Height = dri2_surf->wl_win->height;
471      dri2_surf->dx = dri2_surf->wl_win->dx;
472      dri2_surf->dy = dri2_surf->wl_win->dy;
473
474      for (i = 0; i < WL_BUFFER_COUNT; ++i) {
475         if (dri2_surf->wl_drm_buffer[i])
476            wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
477         dri2_surf->wl_drm_buffer[i]  = NULL;
478         dri2_surf->wl_buffer_lock[i] = 0;
479      }
480   }
481
482   dri2_surf->buffer_count = 0;
483   for (i = 0; i < 2*count; i+=2) {
484      assert(attachments[i] < __DRI_BUFFER_COUNT);
485      assert(dri2_surf->buffer_count < 5);
486
487      dri2_prior_buffer_creation(dri2_surf, attachments[i]);
488
489      if (dri2_surf->dri_buffers[attachments[i]] == NULL) {
490
491         dri2_surf->dri_buffers[attachments[i]] =
492            dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
493                  attachments[i], attachments[i+1],
494                  dri2_surf->base.Width, dri2_surf->base.Height);
495
496         if (!dri2_surf->dri_buffers[attachments[i]])
497            continue;
498
499         if (attachments[i] == __DRI_BUFFER_FRONT_LEFT)
500            dri2_process_front_buffer(dri2_surf, attachments[i+1]);
501         else if (attachments[i] == __DRI_BUFFER_BACK_LEFT)
502            dri2_process_back_buffer(dri2_surf, attachments[i+1]);
503      }
504
505      memcpy(&dri2_surf->buffers[dri2_surf->buffer_count],
506             dri2_surf->dri_buffers[attachments[i]],
507             sizeof(__DRIbuffer));
508
509      dri2_surf->buffer_count++;
510   }
511
512   assert(dri2_surf->base.Type == EGL_PIXMAP_BIT ||
513          dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
514
515   if (dri2_surf->base.Type == EGL_PIXMAP_BIT && !dri2_surf->wl_pix->buffer)
516      dri2_surf->wl_pix->buffer =
517         wayland_create_buffer(dri2_surf,
518			       dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]);
519
520   *out_count = dri2_surf->buffer_count;
521   if (dri2_surf->buffer_count == 0)
522	   return NULL;
523
524   *width = dri2_surf->base.Width;
525   *height = dri2_surf->base.Height;
526
527   return dri2_surf->buffers;
528}
529
530static __DRIbuffer *
531dri2_get_buffers(__DRIdrawable * driDrawable,
532		 int *width, int *height,
533		 unsigned int *attachments, int count,
534		 int *out_count, void *loaderPrivate)
535{
536   unsigned int *attachments_with_format;
537   __DRIbuffer *buffer;
538   const unsigned int format = 32;
539   int i;
540
541   attachments_with_format = calloc(count * 2, sizeof(unsigned int));
542   if (!attachments_with_format) {
543      *out_count = 0;
544      return NULL;
545   }
546
547   for (i = 0; i < count; ++i) {
548      attachments_with_format[2*i] = attachments[i];
549      attachments_with_format[2*i + 1] = format;
550   }
551
552   buffer =
553      dri2_get_buffers_with_format(driDrawable,
554				   width, height,
555				   attachments_with_format, count,
556				   out_count, loaderPrivate);
557
558   free(attachments_with_format);
559
560   return buffer;
561}
562
563
564static void
565dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
566{
567   (void) driDrawable;
568
569   /* FIXME: Does EGL support front buffer rendering at all? */
570
571#if 0
572   struct dri2_egl_surface *dri2_surf = loaderPrivate;
573
574   dri2WaitGL(dri2_surf);
575#else
576   (void) loaderPrivate;
577#endif
578}
579
580static void
581wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
582{
583   struct dri2_egl_surface *dri2_surf = data;
584
585   dri2_surf->frame_callback = NULL;
586   wl_callback_destroy(callback);
587}
588
589static const struct wl_callback_listener frame_listener = {
590	wayland_frame_callback
591};
592
593/**
594 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
595 */
596static EGLBoolean
597dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
598{
599   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
600   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
601   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
602   int ret = 0;
603
604   while (dri2_surf->frame_callback && ret != -1)
605      ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
606   if (ret < 0)
607      return EGL_FALSE;
608
609   dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface);
610   wl_callback_add_listener(dri2_surf->frame_callback,
611                            &frame_listener, dri2_surf);
612   wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback,
613                      dri2_dpy->wl_queue);
614
615   if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
616      pointer_swap(
617	    (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
618	    (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
619
620      dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment =
621	 __DRI_BUFFER_FRONT_LEFT;
622      dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment =
623	 __DRI_BUFFER_BACK_LEFT;
624
625      swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK);
626
627      if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT])
628	 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] =
629	    wayland_create_buffer(dri2_surf,
630		  dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]);
631
632      wl_surface_attach(dri2_surf->wl_win->surface,
633	    dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
634	    dri2_surf->dx, dri2_surf->dy);
635      dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1;
636
637      dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
638      dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
639      /* reset resize growing parameters */
640      dri2_surf->dx = 0;
641      dri2_surf->dy = 0;
642
643      wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
644	    dri2_surf->base.Width, dri2_surf->base.Height);
645
646      wl_surface_commit(dri2_surf->wl_win->surface);
647   }
648
649   _EGLContext *ctx;
650   if (dri2_drv->glFlush) {
651      ctx = _eglGetCurrentContext();
652      if (ctx && ctx->DrawSurface == &dri2_surf->base)
653         dri2_drv->glFlush();
654   }
655
656   (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
657   (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
658
659   return EGL_TRUE;
660}
661
662/**
663 * Called via eglCreateImageKHR(), drv->API.CreateImageKHR().
664 */
665static _EGLImage *
666dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
667			     EGLClientBuffer buffer, const EGLint *attr_list)
668{
669   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
670   struct wl_egl_pixmap *wl_egl_pixmap = (struct wl_egl_pixmap *) buffer;
671   struct dri2_egl_buffer *dri2_buf;
672   EGLint wl_attr_list[] = {
673		EGL_WIDTH,		0,
674		EGL_HEIGHT,		0,
675		EGL_DRM_BUFFER_STRIDE_MESA,	0,
676		EGL_DRM_BUFFER_FORMAT_MESA,	EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
677		EGL_NONE
678   };
679
680   dri2_buf = malloc(sizeof *dri2_buf);
681   if (!dri2_buf)
682           return NULL;
683
684   dri2_buf->dri2_dpy = dri2_dpy;
685   dri2_buf->dri_buffer =
686      dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
687				     __DRI_BUFFER_FRONT_LEFT, 32,
688				     wl_egl_pixmap->width,
689				     wl_egl_pixmap->height);
690
691   wl_egl_pixmap->destroy = dri2_wl_egl_pixmap_destroy;
692   wl_egl_pixmap->driver_private = dri2_buf;
693
694   /* FIXME: Get buffer format from attr_list somehow... or from the
695      wl_egl_piaxmap.  */
696   wl_egl_pixmap->buffer =
697      wl_drm_create_buffer(dri2_dpy->wl_drm,
698			   dri2_buf->dri_buffer->name,
699			   wl_egl_pixmap->width,
700			   wl_egl_pixmap->height,
701			   dri2_buf->dri_buffer->pitch,
702			   WL_DRM_FORMAT_ARGB8888);
703
704   wl_attr_list[1] = wl_egl_pixmap->width;
705   wl_attr_list[3] = wl_egl_pixmap->height;
706   wl_attr_list[5] = dri2_buf->dri_buffer->pitch / 4;
707
708   return dri2_create_image_khr(disp->Driver, disp, ctx, EGL_DRM_BUFFER_MESA,
709	(EGLClientBuffer)(intptr_t) dri2_buf->dri_buffer->name, wl_attr_list);
710}
711
712static _EGLImage *
713dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
714			      _EGLContext *ctx, EGLenum target,
715			      EGLClientBuffer buffer, const EGLint *attr_list)
716{
717   (void) drv;
718
719   switch (target) {
720   case EGL_NATIVE_PIXMAP_KHR:
721      return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
722   default:
723      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
724   }
725}
726
727static int
728dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
729{
730   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
731   int ret = 0;
732
733   dri2_dpy->authenticated = 0;
734
735   wl_drm_authenticate(dri2_dpy->wl_drm, id);
736   if (roundtrip(dri2_dpy) < 0)
737      ret = -1;
738
739   if (!dri2_dpy->authenticated)
740      ret = -1;
741
742   /* reset authenticated */
743   dri2_dpy->authenticated = 1;
744
745   return ret;
746}
747
748/**
749 * Called via eglTerminate(), drv->API.Terminate().
750 */
751static EGLBoolean
752dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
753{
754   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
755
756   _eglReleaseDisplayResources(drv, disp);
757   _eglCleanupDisplay(disp);
758
759   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
760   close(dri2_dpy->fd);
761   dlclose(dri2_dpy->driver);
762   free(dri2_dpy->driver_name);
763   free(dri2_dpy->device_name);
764   wl_drm_destroy(dri2_dpy->wl_drm);
765   if (dri2_dpy->own_device)
766      wl_display_disconnect(dri2_dpy->wl_dpy);
767   free(dri2_dpy);
768   disp->DriverData = NULL;
769
770   return EGL_TRUE;
771}
772
773static void
774drm_handle_device(void *data, struct wl_drm *drm, const char *device)
775{
776   struct dri2_egl_display *dri2_dpy = data;
777   drm_magic_t magic;
778
779   dri2_dpy->device_name = strdup(device);
780   if (!dri2_dpy->device_name)
781      return;
782
783#ifdef O_CLOEXEC
784   dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
785   if (dri2_dpy->fd == -1 && errno == EINVAL)
786#endif
787   {
788      dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
789      if (dri2_dpy->fd != -1)
790         fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
791            FD_CLOEXEC);
792   }
793   if (dri2_dpy->fd == -1) {
794      _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
795	      dri2_dpy->device_name, strerror(errno));
796      return;
797   }
798
799   drmGetMagic(dri2_dpy->fd, &magic);
800   wl_drm_authenticate(dri2_dpy->wl_drm, magic);
801}
802
803static void
804drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
805{
806   struct dri2_egl_display *dri2_dpy = data;
807
808   switch (format) {
809   case WL_DRM_FORMAT_ARGB8888:
810      dri2_dpy->formats |= HAS_ARGB8888;
811      break;
812   case WL_DRM_FORMAT_XRGB8888:
813      dri2_dpy->formats |= HAS_XRGB8888;
814      break;
815   }
816}
817
818static void
819drm_handle_authenticated(void *data, struct wl_drm *drm)
820{
821   struct dri2_egl_display *dri2_dpy = data;
822
823   dri2_dpy->authenticated = 1;
824}
825
826static const struct wl_drm_listener drm_listener = {
827	drm_handle_device,
828	drm_handle_format,
829	drm_handle_authenticated
830};
831
832static void
833registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
834		       const char *interface, uint32_t version)
835{
836   struct dri2_egl_display *dri2_dpy = data;
837
838   if (strcmp(interface, "wl_drm") == 0) {
839      dri2_dpy->wl_drm =
840         wl_registry_bind(registry, name, &wl_drm_interface, 1);
841      wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
842   }
843}
844
845static const struct wl_registry_listener registry_listener = {
846	registry_handle_global
847};
848
849EGLBoolean
850dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
851{
852   struct dri2_egl_display *dri2_dpy;
853   const __DRIconfig *config;
854   uint32_t types;
855   int i;
856   static const unsigned int argb_masks[4] =
857      { 0xff0000, 0xff00, 0xff, 0xff000000 };
858   static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
859
860   drv->API.CreateWindowSurface = dri2_create_window_surface;
861   drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
862   drv->API.DestroySurface = dri2_destroy_surface;
863   drv->API.SwapBuffers = dri2_swap_buffers;
864   drv->API.CreateImageKHR = dri2_wayland_create_image_khr;
865   drv->API.Terminate = dri2_terminate;
866
867   dri2_dpy = malloc(sizeof *dri2_dpy);
868   if (!dri2_dpy)
869      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
870
871   memset(dri2_dpy, 0, sizeof *dri2_dpy);
872
873   disp->DriverData = (void *) dri2_dpy;
874   if (disp->PlatformDisplay == NULL) {
875      dri2_dpy->wl_dpy = wl_display_connect(NULL);
876      if (dri2_dpy->wl_dpy == NULL)
877         goto cleanup_dpy;
878      dri2_dpy->own_device = 1;
879   } else {
880      dri2_dpy->wl_dpy = disp->PlatformDisplay;
881   }
882
883   dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
884   dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
885   wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
886                      dri2_dpy->wl_queue);
887   wl_registry_add_listener(dri2_dpy->wl_registry,
888                            &registry_listener, dri2_dpy);
889   if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
890      goto cleanup_dpy;
891
892   if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
893      goto cleanup_drm;
894
895   if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
896      goto cleanup_fd;
897
898   dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
899   if (dri2_dpy->driver_name == NULL) {
900      _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
901      goto cleanup_fd;
902   }
903
904   if (!dri2_load_driver(disp))
905      goto cleanup_driver_name;
906
907   dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
908   dri2_dpy->dri2_loader_extension.base.version = 3;
909   dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
910   dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
911   dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
912      dri2_get_buffers_with_format;
913
914   dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
915   dri2_dpy->extensions[1] = &image_lookup_extension.base;
916   dri2_dpy->extensions[2] = &use_invalidate.base;
917   dri2_dpy->extensions[3] = NULL;
918
919   if (!dri2_create_screen(disp))
920      goto cleanup_driver;
921
922   types = EGL_WINDOW_BIT | EGL_PIXMAP_BIT;
923   for (i = 0; dri2_dpy->driver_configs[i]; i++) {
924      config = dri2_dpy->driver_configs[i];
925      if (dri2_dpy->formats & HAS_XRGB8888)
926	 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks);
927      if (dri2_dpy->formats & HAS_ARGB8888)
928	 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks);
929   }
930
931   disp->Extensions.KHR_image_pixmap = EGL_TRUE;
932
933   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
934   dri2_dpy->authenticate = dri2_wayland_authenticate;
935
936   /* we're supporting EGL 1.4 */
937   disp->VersionMajor = 1;
938   disp->VersionMinor = 4;
939
940   return EGL_TRUE;
941
942 cleanup_driver:
943   dlclose(dri2_dpy->driver);
944 cleanup_driver_name:
945   free(dri2_dpy->driver_name);
946 cleanup_fd:
947   close(dri2_dpy->fd);
948 cleanup_drm:
949   free(dri2_dpy->device_name);
950   wl_drm_destroy(dri2_dpy->wl_drm);
951 cleanup_dpy:
952   free(dri2_dpy);
953
954   return EGL_FALSE;
955}
956