platform_wayland.c revision f05751aa2af1a8ec83c2d110385aab1b7e735238
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
36#include "egl_dri2.h"
37
38#include <wayland-client.h>
39#include "wayland-drm-client-protocol.h"
40
41static void
42sync_callback(void *data)
43{
44   int *done = data;
45
46   *done = 1;
47}
48
49static void
50force_roundtrip(struct wl_display *display)
51{
52   int done = 0;
53
54   wl_display_sync_callback(display, sync_callback, &done);
55   wl_display_iterate(display, WL_DISPLAY_WRITABLE);
56   while (!done)
57      wl_display_iterate(display, WL_DISPLAY_READABLE);
58}
59
60
61/**
62 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
63 */
64static _EGLSurface *
65dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
66		    _EGLConfig *conf, EGLNativeWindowType window,
67		    const EGLint *attrib_list)
68{
69   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
70   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
71   struct dri2_egl_surface *dri2_surf;
72   struct dri2_egl_buffer *dri2_buf;
73   int i;
74
75   (void) drv;
76
77   dri2_surf = malloc(sizeof *dri2_surf);
78   if (!dri2_surf) {
79      _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
80      return NULL;
81   }
82
83   if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
84      goto cleanup_surf;
85
86   for (i = 0; i < WL_BUFFER_COUNT; ++i)
87      dri2_surf->wl_drm_buffer[i] = NULL;
88
89   for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
90      dri2_surf->dri_buffers[i] = NULL;
91
92   dri2_surf->pending_buffer = NULL;
93   dri2_surf->block_swap_buffers = EGL_FALSE;
94
95   switch (type) {
96   case EGL_WINDOW_BIT:
97      dri2_surf->wl_win = (struct wl_egl_window *) window;
98      dri2_surf->type = DRI2_WINDOW_SURFACE;
99
100      dri2_surf->base.Width =  -1;
101      dri2_surf->base.Height = -1;
102      break;
103   case EGL_PIXMAP_BIT:
104      dri2_surf->wl_pix = (struct wl_egl_pixmap *) window;
105      dri2_surf->type = DRI2_PIXMAP_SURFACE;
106
107      dri2_surf->base.Width  = dri2_surf->wl_pix->width;
108      dri2_surf->base.Height = dri2_surf->wl_pix->height;
109
110      if (dri2_surf->wl_pix->name > 0) {
111         dri2_buf = dri2_surf->wl_pix->driver_private;
112         dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = dri2_buf->dri_buffer;
113      }
114      break;
115   default:
116      goto cleanup_surf;
117   }
118
119   dri2_surf->dri_drawable =
120      (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
121					    type == EGL_WINDOW_BIT ?
122					    dri2_conf->dri_double_config :
123					    dri2_conf->dri_single_config,
124					    dri2_surf);
125   if (dri2_surf->dri_drawable == NULL) {
126      _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
127      goto cleanup_dri_drawable;
128   }
129
130   return &dri2_surf->base;
131
132 cleanup_dri_drawable:
133   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
134 cleanup_surf:
135   free(dri2_surf);
136
137   return NULL;
138}
139
140/**
141 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
142 */
143static _EGLSurface *
144dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
145			   _EGLConfig *conf, EGLNativeWindowType window,
146			   const EGLint *attrib_list)
147{
148   return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
149			      window, attrib_list);
150}
151
152static _EGLSurface *
153dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
154			   _EGLConfig *conf, EGLNativePixmapType pixmap,
155			   const EGLint *attrib_list)
156{
157   return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
158			      pixmap, attrib_list);
159}
160
161/**
162 * Called via eglDestroySurface(), drv->API.DestroySurface().
163 */
164static EGLBoolean
165dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
166{
167   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
168   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
169   int i;
170
171   (void) drv;
172
173   if (!_eglPutSurface(surf))
174      return EGL_TRUE;
175
176   (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
177
178   for (i = 0; i < WL_BUFFER_COUNT; ++i)
179      if (dri2_surf->wl_drm_buffer[i])
180         wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
181
182   for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
183      if (dri2_surf->dri_buffers[i] && !(i == __DRI_BUFFER_FRONT_LEFT &&
184          dri2_surf->type == DRI2_PIXMAP_SURFACE))
185         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
186                                       dri2_surf->dri_buffers[i]);
187
188   free(surf);
189
190   return EGL_TRUE;
191}
192
193static void
194dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
195{
196   struct dri2_egl_buffer *dri2_buf = egl_pixmap->driver_private;
197
198   assert(dri2_buf);
199
200   dri2_buf->dri2_dpy->dri2->releaseBuffer(dri2_buf->dri2_dpy->dri_screen,
201                                           dri2_buf->dri_buffer);
202
203   free(dri2_buf);
204
205   egl_pixmap->driver_private = NULL;
206   egl_pixmap->destroy = NULL;
207   egl_pixmap->name = 0;
208}
209
210static void
211dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
212{
213   struct dri2_egl_display *dri2_dpy =
214      dri2_egl_display(dri2_surf->base.Resource.Display);
215
216   (void) format;
217
218   switch (dri2_surf->type) {
219   case DRI2_WINDOW_SURFACE:
220      /* allocate a front buffer for our double-buffered window*/
221      dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] =
222         dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
223               __DRI_BUFFER_FRONT_LEFT, format,
224               dri2_surf->base.Width, dri2_surf->base.Height);
225      break;
226   default:
227      break;
228   }
229}
230
231static void
232dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
233{
234   struct dri2_egl_display *dri2_dpy =
235      dri2_egl_display(dri2_surf->base.Resource.Display);
236   struct dri2_egl_buffer *dri2_buf;
237
238   switch (dri2_surf->type) {
239   case DRI2_PIXMAP_SURFACE:
240      dri2_buf = malloc(sizeof *dri2_buf);
241      if (!dri2_buf)
242         return;
243
244      dri2_buf->dri_buffer = dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT];
245      dri2_buf->dri2_dpy   = dri2_dpy;
246
247      dri2_surf->wl_pix->name           = dri2_buf->dri_buffer->name;
248      dri2_surf->wl_pix->stride         = dri2_buf->dri_buffer->pitch;
249      dri2_surf->wl_pix->driver_private = dri2_buf;
250      dri2_surf->wl_pix->destroy        = dri2_wl_egl_pixmap_destroy;
251      break;
252   default:
253      break;
254   }
255}
256
257static void
258dri2_release_pending_buffer(void *data)
259{
260   struct dri2_egl_surface *dri2_surf = data;
261   struct dri2_egl_display *dri2_dpy =
262      dri2_egl_display(dri2_surf->base.Resource.Display);
263
264   /* FIXME: print internal error */
265   if (!dri2_surf->pending_buffer)
266      return;
267
268   dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
269                                 dri2_surf->pending_buffer);
270   dri2_surf->pending_buffer = NULL;
271}
272
273static void
274dri2_release_buffers(struct dri2_egl_surface *dri2_surf)
275{
276   struct dri2_egl_display *dri2_dpy =
277      dri2_egl_display(dri2_surf->base.Resource.Display);
278   int i;
279
280   for (i = 0; i < __DRI_BUFFER_COUNT; ++i) {
281      if (dri2_surf->dri_buffers[i]) {
282         switch (i) {
283         case __DRI_BUFFER_FRONT_LEFT:
284            if (dri2_surf->pending_buffer)
285               force_roundtrip(dri2_dpy->wl_dpy->display);
286            dri2_surf->pending_buffer = dri2_surf->dri_buffers[i];
287            wl_display_sync_callback(dri2_dpy->wl_dpy->display,
288                                     dri2_release_pending_buffer, dri2_surf);
289            break;
290         default:
291            dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
292                                          dri2_surf->dri_buffers[i]);
293            break;
294         }
295         dri2_surf->dri_buffers[i] = NULL;
296      }
297   }
298}
299
300static __DRIbuffer *
301dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
302			     int *width, int *height,
303			     unsigned int *attachments, int count,
304			     int *out_count, void *loaderPrivate)
305{
306   struct dri2_egl_surface *dri2_surf = loaderPrivate;
307   struct dri2_egl_display *dri2_dpy =
308      dri2_egl_display(dri2_surf->base.Resource.Display);
309   int i;
310
311   if (dri2_surf->type == DRI2_WINDOW_SURFACE &&
312       (dri2_surf->base.Width != dri2_surf->wl_win->width ||
313        dri2_surf->base.Height != dri2_surf->wl_win->height)) {
314
315      dri2_release_buffers(dri2_surf);
316
317      dri2_surf->base.Width  = dri2_surf->wl_win->width;
318      dri2_surf->base.Height = dri2_surf->wl_win->height;
319      dri2_surf->dx = dri2_surf->wl_win->dx;
320      dri2_surf->dy = dri2_surf->wl_win->dy;
321
322      for (i = 0; i < WL_BUFFER_COUNT; ++i) {
323         if (dri2_surf->wl_drm_buffer[i])
324            wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
325         dri2_surf->wl_drm_buffer[i]  = NULL;
326      }
327   }
328
329   dri2_surf->buffer_count = 0;
330   for (i = 0; i < 2*count; i+=2) {
331      assert(attachments[i] < __DRI_BUFFER_COUNT);
332      assert(dri2_surf->buffer_count < 5);
333
334      if (dri2_surf->dri_buffers[attachments[i]] == NULL) {
335
336         dri2_surf->dri_buffers[attachments[i]] =
337            dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
338                  attachments[i], attachments[i+1],
339                  dri2_surf->base.Width, dri2_surf->base.Height);
340
341         if (!dri2_surf->dri_buffers[attachments[i]])
342            continue;
343
344         if (attachments[i] == __DRI_BUFFER_FRONT_LEFT)
345            dri2_process_front_buffer(dri2_surf, attachments[i+1]);
346         else if (attachments[i] == __DRI_BUFFER_BACK_LEFT)
347            dri2_process_back_buffer(dri2_surf, attachments[i+1]);
348      }
349
350      memcpy(&dri2_surf->buffers[dri2_surf->buffer_count],
351             dri2_surf->dri_buffers[attachments[i]],
352             sizeof(__DRIbuffer));
353
354      dri2_surf->buffer_count++;
355   }
356
357   assert(dri2_surf->type == DRI2_PIXMAP_SURFACE ||
358          dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
359
360   *out_count = dri2_surf->buffer_count;
361   if (dri2_surf->buffer_count == 0)
362	   return NULL;
363
364   *width = dri2_surf->base.Width;
365   *height = dri2_surf->base.Height;
366
367   return dri2_surf->buffers;
368}
369
370static __DRIbuffer *
371dri2_get_buffers(__DRIdrawable * driDrawable,
372		 int *width, int *height,
373		 unsigned int *attachments, int count,
374		 int *out_count, void *loaderPrivate)
375{
376   unsigned int *attachments_with_format;
377   __DRIbuffer *buffer;
378   const unsigned int format = 32;
379   int i;
380
381   attachments_with_format = calloc(count * 2, sizeof(unsigned int));
382   if (!attachments_with_format) {
383      *out_count = 0;
384      return NULL;
385   }
386
387   for (i = 0; i < count; ++i) {
388      attachments_with_format[2*i] = attachments[i];
389      attachments_with_format[2*i + 1] = format;
390   }
391
392   buffer =
393      dri2_get_buffers_with_format(driDrawable,
394				   width, height,
395				   attachments_with_format, count,
396				   out_count, loaderPrivate);
397
398   free(attachments_with_format);
399
400   return buffer;
401}
402
403
404static void
405dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
406{
407   (void) driDrawable;
408
409   /* FIXME: Does EGL support front buffer rendering at all? */
410
411#if 0
412   struct dri2_egl_surface *dri2_surf = loaderPrivate;
413
414   dri2WaitGL(dri2_surf);
415#else
416   (void) loaderPrivate;
417#endif
418}
419
420static struct wl_buffer *
421wayland_create_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
422{
423   struct dri2_egl_display *dri2_dpy =
424      dri2_egl_display(dri2_surf->base.Resource.Display);
425
426   return wl_drm_create_buffer(dri2_dpy->wl_dpy->drm, buffer->name,
427                               dri2_surf->base.Width, dri2_surf->base.Height,
428                               buffer->pitch, dri2_surf->wl_win->visual);
429}
430
431static void
432wayland_frame_callback(struct wl_surface *surface, void *data, uint32_t time)
433{
434   struct dri2_egl_surface *dri2_surf = data;
435
436   dri2_surf->block_swap_buffers = EGL_FALSE;
437}
438
439static inline void
440pointer_swap(const void **p1, const void **p2)
441{
442   const void *tmp = *p1;
443   *p1 = *p2;
444   *p2 = tmp;
445}
446
447/**
448 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
449 */
450static EGLBoolean
451dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
452{
453   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
454   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
455   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
456
457   while (dri2_surf->block_swap_buffers)
458      wl_display_iterate(dri2_dpy->wl_dpy->display, WL_DISPLAY_READABLE);
459
460   dri2_surf->block_swap_buffers = EGL_TRUE;
461   wl_display_frame_callback(dri2_dpy->wl_dpy->display,
462	 		     dri2_surf->wl_win->surface,
463			     wayland_frame_callback, dri2_surf);
464
465   if (dri2_surf->type == DRI2_WINDOW_SURFACE) {
466      pointer_swap(
467	    (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
468	    (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
469
470      dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment =
471	 __DRI_BUFFER_FRONT_LEFT;
472      dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment =
473	 __DRI_BUFFER_BACK_LEFT;
474
475      pointer_swap((const void **) &dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
476		   (const void **) &dri2_surf->wl_drm_buffer[WL_BUFFER_BACK]);
477
478      if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT])
479	 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] =
480	    wayland_create_buffer(dri2_surf,
481		  dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]);
482
483      wl_surface_attach(dri2_surf->wl_win->surface,
484	    dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
485	    dri2_surf->dx, dri2_surf->dy);
486
487      dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
488      dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
489      /* reset resize growing parameters */
490      dri2_surf->dx = 0;
491      dri2_surf->dy = 0;
492
493      wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
494	    dri2_surf->base.Width, dri2_surf->base.Height);
495   }
496
497   _EGLContext *ctx;
498   if (dri2_drv->glFlush) {
499      ctx = _eglGetCurrentContext();
500      if (ctx && ctx->DrawSurface == &dri2_surf->base)
501         dri2_drv->glFlush();
502   }
503
504   (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
505   (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
506
507   return EGL_TRUE;
508}
509
510/**
511 * Called via eglCreateImageKHR(), drv->API.CreateImageKHR().
512 */
513static _EGLImage *
514dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
515			     EGLClientBuffer buffer, const EGLint *attr_list)
516{
517   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
518   struct wl_egl_pixmap *wl_egl_pixmap = (struct wl_egl_pixmap *) buffer;
519   struct dri2_egl_buffer *dri2_buf;
520   EGLint wl_attr_list[] = {
521		EGL_WIDTH,		0,
522		EGL_HEIGHT,		0,
523		EGL_DRM_BUFFER_STRIDE_MESA,	0,
524		EGL_DRM_BUFFER_FORMAT_MESA,	EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
525		EGL_NONE
526   };
527
528   dri2_buf = malloc(sizeof *dri2_buf);
529   if (!dri2_buf)
530           return NULL;
531
532   dri2_buf->dri2_dpy = dri2_dpy;
533   dri2_buf->dri_buffer =
534      dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
535				     __DRI_BUFFER_FRONT_LEFT, 32,
536				     wl_egl_pixmap->width,
537				     wl_egl_pixmap->height);
538
539   wl_egl_pixmap->name    = dri2_buf->dri_buffer->name;
540   wl_egl_pixmap->stride  = dri2_buf->dri_buffer->pitch;
541   wl_egl_pixmap->destroy = dri2_wl_egl_pixmap_destroy;
542   wl_egl_pixmap->driver_private = dri2_buf;
543
544   wl_attr_list[1] = wl_egl_pixmap->width;
545   wl_attr_list[3] = wl_egl_pixmap->height;
546   wl_attr_list[5] = wl_egl_pixmap->stride / 4;
547
548
549   return dri2_create_image_khr(disp->Driver, disp, ctx, EGL_DRM_BUFFER_MESA,
550	       (EGLClientBuffer)(intptr_t) wl_egl_pixmap->name, wl_attr_list);
551}
552
553static _EGLImage *
554dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
555			      _EGLContext *ctx, EGLenum target,
556			      EGLClientBuffer buffer, const EGLint *attr_list)
557{
558   (void) drv;
559
560   switch (target) {
561   case EGL_NATIVE_PIXMAP_KHR:
562      return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
563   default:
564      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
565   }
566}
567
568static int
569dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
570{
571   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
572   int ret = 0;
573
574   dri2_dpy->wl_dpy->authenticated = false;
575
576   wl_drm_authenticate(dri2_dpy->wl_dpy->drm, id);
577   force_roundtrip(dri2_dpy->wl_dpy->display);
578
579   if (!dri2_dpy->wl_dpy->authenticated)
580      ret = -1;
581
582   /* reset authenticated */
583   dri2_dpy->wl_dpy->authenticated = true;
584
585   return ret;
586}
587
588/**
589 * Called via eglTerminate(), drv->API.Terminate().
590 */
591static EGLBoolean
592dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
593{
594   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
595
596   _eglReleaseDisplayResources(drv, disp);
597   _eglCleanupDisplay(disp);
598
599   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
600   close(dri2_dpy->fd);
601   dlclose(dri2_dpy->driver);
602   free(dri2_dpy->driver_name);
603   free(dri2_dpy);
604   disp->DriverData = NULL;
605
606   return EGL_TRUE;
607}
608
609EGLBoolean
610dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
611{
612   struct dri2_egl_display *dri2_dpy;
613   int i;
614
615   drv->API.CreateWindowSurface = dri2_create_window_surface;
616   drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
617   drv->API.DestroySurface = dri2_destroy_surface;
618   drv->API.SwapBuffers = dri2_swap_buffers;
619   drv->API.CreateImageKHR = dri2_wayland_create_image_khr;
620   drv->API.Terminate = dri2_terminate;
621
622   dri2_dpy = malloc(sizeof *dri2_dpy);
623   if (!dri2_dpy)
624      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
625
626   memset(dri2_dpy, 0, sizeof *dri2_dpy);
627
628   disp->DriverData = (void *) dri2_dpy;
629   dri2_dpy->wl_dpy = disp->PlatformDisplay;
630
631   if (dri2_dpy->wl_dpy->fd == -1)
632      force_roundtrip(dri2_dpy->wl_dpy->display);
633   if (dri2_dpy->wl_dpy->fd == -1)
634      goto cleanup_dpy;
635
636   dri2_dpy->fd = dup(dri2_dpy->wl_dpy->fd);
637   if (dri2_dpy->fd < 0) {
638      _eglError(EGL_BAD_ALLOC, "DRI2: failed to dup fd");
639      goto cleanup_dpy;
640   }
641
642   if (!dri2_dpy->wl_dpy->authenticated)
643      force_roundtrip(dri2_dpy->wl_dpy->display);
644   if (!dri2_dpy->wl_dpy->authenticated)
645      goto cleanup_dpy;
646
647   dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
648   if (dri2_dpy->driver_name == NULL) {
649      _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
650      goto cleanup_fd;
651   }
652
653   dri2_dpy->device_name = strdup(dri2_dpy->wl_dpy->device_name);
654   if (dri2_dpy->device_name == NULL) {
655      _eglError(EGL_BAD_ALLOC, "DRI2: failed to get device name");
656      goto cleanup_driver_name;
657   }
658
659   if (!dri2_load_driver(disp))
660      goto cleanup_device_name;
661
662   dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
663   dri2_dpy->dri2_loader_extension.base.version = 3;
664   dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
665   dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
666   dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
667      dri2_get_buffers_with_format;
668
669   dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
670   dri2_dpy->extensions[1] = &image_lookup_extension.base;
671   dri2_dpy->extensions[2] = NULL;
672
673   if (!dri2_create_screen(disp))
674      goto cleanup_driver;
675
676   for (i = 0; dri2_dpy->driver_configs[i]; i++)
677      dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0,
678		      EGL_WINDOW_BIT | EGL_PIXMAP_BIT, NULL);
679
680
681   disp->Extensions.KHR_image_pixmap = EGL_TRUE;
682
683   disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
684   dri2_dpy->authenticate = dri2_wayland_authenticate;
685
686   /* we're supporting EGL 1.4 */
687   disp->VersionMajor = 1;
688   disp->VersionMinor = 4;
689
690   return EGL_TRUE;
691
692 cleanup_driver:
693   dlclose(dri2_dpy->driver);
694 cleanup_device_name:
695   free(dri2_dpy->device_name);
696 cleanup_driver_name:
697   free(dri2_dpy->driver_name);
698 cleanup_fd:
699   close(dri2_dpy->fd);
700 cleanup_dpy:
701   free(dri2_dpy);
702
703   return EGL_FALSE;
704}
705