egl/wayland: Dispatch the event queue before get_buffers
[mesa.git] / src / egl / drivers / dri2 / platform_wayland.c
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
43 enum wl_drm_format_flags {
44 HAS_ARGB8888 = 1,
45 HAS_XRGB8888 = 2
46 };
47
48 static void
49 sync_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
57 static const struct wl_callback_listener sync_listener = {
58 sync_callback
59 };
60
61 static int
62 roundtrip(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
76 static void
77 wl_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
96 static struct wl_buffer_listener wl_buffer_listener = {
97 wl_buffer_release
98 };
99
100 static void
101 resize_callback(struct wl_egl_window *wl_win, void *data)
102 {
103 struct dri2_egl_surface *dri2_surf = data;
104 struct dri2_egl_display *dri2_dpy =
105 dri2_egl_display(dri2_surf->base.Resource.Display);
106
107 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
108 }
109
110 /**
111 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
112 */
113 static _EGLSurface *
114 dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
115 _EGLConfig *conf, EGLNativeWindowType window,
116 const EGLint *attrib_list)
117 {
118 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
119 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
120 struct dri2_egl_surface *dri2_surf;
121 int i;
122
123 (void) drv;
124
125 dri2_surf = malloc(sizeof *dri2_surf);
126 if (!dri2_surf) {
127 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
128 return NULL;
129 }
130
131 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
132 goto cleanup_surf;
133
134 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
135 dri2_surf->wl_drm_buffer[i] = NULL;
136 dri2_surf->wl_buffer_lock[i] = 0;
137 }
138
139 for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
140 dri2_surf->dri_buffers[i] = NULL;
141
142 dri2_surf->pending_buffer = NULL;
143 dri2_surf->third_buffer = NULL;
144 dri2_surf->frame_callback = NULL;
145
146 if (conf->AlphaSize == 0)
147 dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
148 else
149 dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
150
151 switch (type) {
152 case EGL_WINDOW_BIT:
153 dri2_surf->wl_win = (struct wl_egl_window *) window;
154
155 dri2_surf->wl_win->private = dri2_surf;
156 dri2_surf->wl_win->resize_callback = resize_callback;
157
158 dri2_surf->base.Width = -1;
159 dri2_surf->base.Height = -1;
160 break;
161 default:
162 goto cleanup_surf;
163 }
164
165 dri2_surf->dri_drawable =
166 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
167 type == EGL_WINDOW_BIT ?
168 dri2_conf->dri_double_config :
169 dri2_conf->dri_single_config,
170 dri2_surf);
171 if (dri2_surf->dri_drawable == NULL) {
172 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
173 goto cleanup_dri_drawable;
174 }
175
176 return &dri2_surf->base;
177
178 cleanup_dri_drawable:
179 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
180 cleanup_surf:
181 free(dri2_surf);
182
183 return NULL;
184 }
185
186 /**
187 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
188 */
189 static _EGLSurface *
190 dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
191 _EGLConfig *conf, EGLNativeWindowType window,
192 const EGLint *attrib_list)
193 {
194 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
195 window, attrib_list);
196 }
197
198 /**
199 * Called via eglDestroySurface(), drv->API.DestroySurface().
200 */
201 static EGLBoolean
202 dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
203 {
204 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
205 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
206 int i;
207
208 (void) drv;
209
210 if (!_eglPutSurface(surf))
211 return EGL_TRUE;
212
213 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
214
215 for (i = 0; i < WL_BUFFER_COUNT; ++i)
216 if (dri2_surf->wl_drm_buffer[i])
217 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
218
219 for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
220 if (dri2_surf->dri_buffers[i])
221 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
222 dri2_surf->dri_buffers[i]);
223
224 if (dri2_surf->third_buffer) {
225 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
226 dri2_surf->third_buffer);
227 }
228
229 if (dri2_surf->frame_callback)
230 wl_callback_destroy(dri2_surf->frame_callback);
231
232
233 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
234 dri2_surf->wl_win->private = NULL;
235 dri2_surf->wl_win->resize_callback = NULL;
236 }
237
238 free(surf);
239
240 return EGL_TRUE;
241 }
242
243 static struct wl_buffer *
244 wayland_create_buffer(struct dri2_egl_surface *dri2_surf,
245 __DRIbuffer *buffer)
246 {
247 struct dri2_egl_display *dri2_dpy =
248 dri2_egl_display(dri2_surf->base.Resource.Display);
249 struct wl_buffer *buf;
250
251 buf = wl_drm_create_buffer(dri2_dpy->wl_drm, buffer->name,
252 dri2_surf->base.Width, dri2_surf->base.Height,
253 buffer->pitch, dri2_surf->format);
254 wl_buffer_add_listener(buf, &wl_buffer_listener, dri2_surf);
255
256 return buf;
257 }
258
259 static void
260 dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
261 {
262 struct dri2_egl_display *dri2_dpy =
263 dri2_egl_display(dri2_surf->base.Resource.Display);
264
265 (void) format;
266
267 switch (dri2_surf->base.Type) {
268 case EGL_WINDOW_BIT:
269 /* allocate a front buffer for our double-buffered window*/
270 if (dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] != NULL)
271 break;
272 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] =
273 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
274 __DRI_BUFFER_FRONT_LEFT, format,
275 dri2_surf->base.Width, dri2_surf->base.Height);
276 break;
277 default:
278 break;
279 }
280 }
281
282 static void
283 dri2_release_pending_buffer(void *data,
284 struct wl_callback *callback, uint32_t time)
285 {
286 struct dri2_egl_surface *dri2_surf = data;
287 struct dri2_egl_display *dri2_dpy =
288 dri2_egl_display(dri2_surf->base.Resource.Display);
289
290 /* FIXME: print internal error */
291 if (!dri2_surf->pending_buffer)
292 return;
293
294 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
295 dri2_surf->pending_buffer);
296 dri2_surf->pending_buffer = NULL;
297
298 wl_callback_destroy(callback);
299 }
300
301 static const struct wl_callback_listener release_buffer_listener = {
302 dri2_release_pending_buffer
303 };
304
305 static void
306 dri2_release_buffers(struct dri2_egl_surface *dri2_surf)
307 {
308 struct dri2_egl_display *dri2_dpy =
309 dri2_egl_display(dri2_surf->base.Resource.Display);
310 struct wl_callback *callback;
311 int i;
312
313 if (dri2_surf->third_buffer) {
314 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
315 dri2_surf->third_buffer);
316 dri2_surf->third_buffer = NULL;
317 }
318
319 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) {
320 if (dri2_surf->dri_buffers[i]) {
321 switch (i) {
322 case __DRI_BUFFER_FRONT_LEFT:
323 if (dri2_surf->pending_buffer)
324 roundtrip(dri2_dpy);
325 dri2_surf->pending_buffer = dri2_surf->dri_buffers[i];
326 callback = wl_display_sync(dri2_dpy->wl_dpy);
327 wl_callback_add_listener(callback,
328 &release_buffer_listener, dri2_surf);
329 wl_proxy_set_queue((struct wl_proxy *) callback,
330 dri2_dpy->wl_queue);
331 break;
332 default:
333 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
334 dri2_surf->dri_buffers[i]);
335 break;
336 }
337 dri2_surf->dri_buffers[i] = NULL;
338 }
339 }
340 }
341
342 static inline void
343 pointer_swap(const void **p1, const void **p2)
344 {
345 const void *tmp = *p1;
346 *p1 = *p2;
347 *p2 = tmp;
348 }
349
350 static void
351 destroy_third_buffer(struct dri2_egl_surface *dri2_surf)
352 {
353 struct dri2_egl_display *dri2_dpy =
354 dri2_egl_display(dri2_surf->base.Resource.Display);
355
356 if (dri2_surf->third_buffer == NULL)
357 return;
358
359 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
360 dri2_surf->third_buffer);
361 dri2_surf->third_buffer = NULL;
362
363 if (dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD])
364 wl_buffer_destroy(dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD]);
365 dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD] = NULL;
366 dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD] = 0;
367 }
368
369 static void
370 swap_wl_buffers(struct dri2_egl_surface *dri2_surf,
371 enum wayland_buffer_type a, enum wayland_buffer_type b)
372 {
373 int tmp;
374
375 tmp = dri2_surf->wl_buffer_lock[a];
376 dri2_surf->wl_buffer_lock[a] = dri2_surf->wl_buffer_lock[b];
377 dri2_surf->wl_buffer_lock[b] = tmp;
378
379 pointer_swap((const void **) &dri2_surf->wl_drm_buffer[a],
380 (const void **) &dri2_surf->wl_drm_buffer[b]);
381 }
382
383 static void
384 swap_back_and_third(struct dri2_egl_surface *dri2_surf)
385 {
386 if (dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD])
387 destroy_third_buffer(dri2_surf);
388
389 pointer_swap((const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT],
390 (const void **) &dri2_surf->third_buffer);
391
392 swap_wl_buffers(dri2_surf, WL_BUFFER_BACK, WL_BUFFER_THIRD);
393 }
394
395 static void
396 dri2_prior_buffer_creation(struct dri2_egl_surface *dri2_surf,
397 unsigned int type)
398 {
399 switch (type) {
400 case __DRI_BUFFER_BACK_LEFT:
401 if (dri2_surf->wl_buffer_lock[WL_BUFFER_BACK])
402 swap_back_and_third(dri2_surf);
403 else if (dri2_surf->third_buffer)
404 destroy_third_buffer(dri2_surf);
405 break;
406 default:
407 break;
408
409 }
410 }
411
412 static __DRIbuffer *
413 dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
414 int *width, int *height,
415 unsigned int *attachments, int count,
416 int *out_count, void *loaderPrivate)
417 {
418 struct dri2_egl_surface *dri2_surf = loaderPrivate;
419 struct dri2_egl_display *dri2_dpy =
420 dri2_egl_display(dri2_surf->base.Resource.Display);
421 int i;
422
423 /* There might be a buffer release already queued that wasn't processed */
424 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
425
426 if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
427 (dri2_surf->base.Width != dri2_surf->wl_win->width ||
428 dri2_surf->base.Height != dri2_surf->wl_win->height)) {
429
430 dri2_release_buffers(dri2_surf);
431
432 dri2_surf->base.Width = dri2_surf->wl_win->width;
433 dri2_surf->base.Height = dri2_surf->wl_win->height;
434 dri2_surf->dx = dri2_surf->wl_win->dx;
435 dri2_surf->dy = dri2_surf->wl_win->dy;
436
437 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
438 if (dri2_surf->wl_drm_buffer[i])
439 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
440 dri2_surf->wl_drm_buffer[i] = NULL;
441 dri2_surf->wl_buffer_lock[i] = 0;
442 }
443 }
444
445 dri2_surf->buffer_count = 0;
446 for (i = 0; i < 2*count; i+=2) {
447 assert(attachments[i] < __DRI_BUFFER_COUNT);
448 assert(dri2_surf->buffer_count < 5);
449
450 dri2_prior_buffer_creation(dri2_surf, attachments[i]);
451
452 if (dri2_surf->dri_buffers[attachments[i]] == NULL) {
453
454 dri2_surf->dri_buffers[attachments[i]] =
455 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
456 attachments[i], attachments[i+1],
457 dri2_surf->base.Width, dri2_surf->base.Height);
458
459 if (!dri2_surf->dri_buffers[attachments[i]])
460 continue;
461
462 if (attachments[i] == __DRI_BUFFER_BACK_LEFT)
463 dri2_process_back_buffer(dri2_surf, attachments[i+1]);
464 }
465
466 memcpy(&dri2_surf->buffers[dri2_surf->buffer_count],
467 dri2_surf->dri_buffers[attachments[i]],
468 sizeof(__DRIbuffer));
469
470 dri2_surf->buffer_count++;
471 }
472
473 assert(dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
474
475 *out_count = dri2_surf->buffer_count;
476 if (dri2_surf->buffer_count == 0)
477 return NULL;
478
479 *width = dri2_surf->base.Width;
480 *height = dri2_surf->base.Height;
481
482 return dri2_surf->buffers;
483 }
484
485 static __DRIbuffer *
486 dri2_get_buffers(__DRIdrawable * driDrawable,
487 int *width, int *height,
488 unsigned int *attachments, int count,
489 int *out_count, void *loaderPrivate)
490 {
491 unsigned int *attachments_with_format;
492 __DRIbuffer *buffer;
493 const unsigned int format = 32;
494 int i;
495
496 attachments_with_format = calloc(count * 2, sizeof(unsigned int));
497 if (!attachments_with_format) {
498 *out_count = 0;
499 return NULL;
500 }
501
502 for (i = 0; i < count; ++i) {
503 attachments_with_format[2*i] = attachments[i];
504 attachments_with_format[2*i + 1] = format;
505 }
506
507 buffer =
508 dri2_get_buffers_with_format(driDrawable,
509 width, height,
510 attachments_with_format, count,
511 out_count, loaderPrivate);
512
513 free(attachments_with_format);
514
515 return buffer;
516 }
517
518
519 static void
520 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
521 {
522 (void) driDrawable;
523
524 /* FIXME: Does EGL support front buffer rendering at all? */
525
526 #if 0
527 struct dri2_egl_surface *dri2_surf = loaderPrivate;
528
529 dri2WaitGL(dri2_surf);
530 #else
531 (void) loaderPrivate;
532 #endif
533 }
534
535 static void
536 wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
537 {
538 struct dri2_egl_surface *dri2_surf = data;
539
540 dri2_surf->frame_callback = NULL;
541 wl_callback_destroy(callback);
542 }
543
544 static const struct wl_callback_listener frame_listener = {
545 wayland_frame_callback
546 };
547
548 /**
549 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
550 */
551 static EGLBoolean
552 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
553 {
554 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
555 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
556 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
557 int ret = 0;
558
559 while (dri2_surf->frame_callback && ret != -1)
560 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
561 if (ret < 0)
562 return EGL_FALSE;
563
564 dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface);
565 wl_callback_add_listener(dri2_surf->frame_callback,
566 &frame_listener, dri2_surf);
567 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback,
568 dri2_dpy->wl_queue);
569
570 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
571 pointer_swap(
572 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
573 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
574
575 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment =
576 __DRI_BUFFER_FRONT_LEFT;
577 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment =
578 __DRI_BUFFER_BACK_LEFT;
579
580 swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK);
581
582 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT])
583 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] =
584 wayland_create_buffer(dri2_surf,
585 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]);
586
587 wl_surface_attach(dri2_surf->wl_win->surface,
588 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
589 dri2_surf->dx, dri2_surf->dy);
590 dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1;
591
592 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
593 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
594 /* reset resize growing parameters */
595 dri2_surf->dx = 0;
596 dri2_surf->dy = 0;
597
598 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
599 dri2_surf->base.Width, dri2_surf->base.Height);
600
601 wl_surface_commit(dri2_surf->wl_win->surface);
602 }
603
604 _EGLContext *ctx;
605 if (dri2_drv->glFlush) {
606 ctx = _eglGetCurrentContext();
607 if (ctx && ctx->DrawSurface == &dri2_surf->base)
608 dri2_drv->glFlush();
609 }
610
611 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
612 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
613
614 return EGL_TRUE;
615 }
616
617 static int
618 dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
619 {
620 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
621 int ret = 0;
622
623 dri2_dpy->authenticated = 0;
624
625 wl_drm_authenticate(dri2_dpy->wl_drm, id);
626 if (roundtrip(dri2_dpy) < 0)
627 ret = -1;
628
629 if (!dri2_dpy->authenticated)
630 ret = -1;
631
632 /* reset authenticated */
633 dri2_dpy->authenticated = 1;
634
635 return ret;
636 }
637
638 /**
639 * Called via eglTerminate(), drv->API.Terminate().
640 */
641 static EGLBoolean
642 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
643 {
644 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
645
646 _eglReleaseDisplayResources(drv, disp);
647 _eglCleanupDisplay(disp);
648
649 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
650 close(dri2_dpy->fd);
651 dlclose(dri2_dpy->driver);
652 free(dri2_dpy->driver_name);
653 free(dri2_dpy->device_name);
654 wl_drm_destroy(dri2_dpy->wl_drm);
655 if (dri2_dpy->own_device)
656 wl_display_disconnect(dri2_dpy->wl_dpy);
657 free(dri2_dpy);
658 disp->DriverData = NULL;
659
660 return EGL_TRUE;
661 }
662
663 static void
664 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
665 {
666 struct dri2_egl_display *dri2_dpy = data;
667 drm_magic_t magic;
668
669 dri2_dpy->device_name = strdup(device);
670 if (!dri2_dpy->device_name)
671 return;
672
673 #ifdef O_CLOEXEC
674 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
675 if (dri2_dpy->fd == -1 && errno == EINVAL)
676 #endif
677 {
678 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
679 if (dri2_dpy->fd != -1)
680 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
681 FD_CLOEXEC);
682 }
683 if (dri2_dpy->fd == -1) {
684 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
685 dri2_dpy->device_name, strerror(errno));
686 return;
687 }
688
689 drmGetMagic(dri2_dpy->fd, &magic);
690 wl_drm_authenticate(dri2_dpy->wl_drm, magic);
691 }
692
693 static void
694 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
695 {
696 struct dri2_egl_display *dri2_dpy = data;
697
698 switch (format) {
699 case WL_DRM_FORMAT_ARGB8888:
700 dri2_dpy->formats |= HAS_ARGB8888;
701 break;
702 case WL_DRM_FORMAT_XRGB8888:
703 dri2_dpy->formats |= HAS_XRGB8888;
704 break;
705 }
706 }
707
708 static void
709 drm_handle_authenticated(void *data, struct wl_drm *drm)
710 {
711 struct dri2_egl_display *dri2_dpy = data;
712
713 dri2_dpy->authenticated = 1;
714 }
715
716 static const struct wl_drm_listener drm_listener = {
717 drm_handle_device,
718 drm_handle_format,
719 drm_handle_authenticated
720 };
721
722 static void
723 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
724 const char *interface, uint32_t version)
725 {
726 struct dri2_egl_display *dri2_dpy = data;
727
728 if (strcmp(interface, "wl_drm") == 0) {
729 dri2_dpy->wl_drm =
730 wl_registry_bind(registry, name, &wl_drm_interface, 1);
731 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
732 }
733 }
734
735 static const struct wl_registry_listener registry_listener = {
736 registry_handle_global
737 };
738
739 EGLBoolean
740 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
741 {
742 struct dri2_egl_display *dri2_dpy;
743 const __DRIconfig *config;
744 uint32_t types;
745 int i;
746 static const unsigned int argb_masks[4] =
747 { 0xff0000, 0xff00, 0xff, 0xff000000 };
748 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
749
750 drv->API.CreateWindowSurface = dri2_create_window_surface;
751 drv->API.DestroySurface = dri2_destroy_surface;
752 drv->API.SwapBuffers = dri2_swap_buffers;
753 drv->API.Terminate = dri2_terminate;
754
755 dri2_dpy = calloc(1, sizeof *dri2_dpy);
756 if (!dri2_dpy)
757 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
758
759 disp->DriverData = (void *) dri2_dpy;
760 if (disp->PlatformDisplay == NULL) {
761 dri2_dpy->wl_dpy = wl_display_connect(NULL);
762 if (dri2_dpy->wl_dpy == NULL)
763 goto cleanup_dpy;
764 dri2_dpy->own_device = 1;
765 } else {
766 dri2_dpy->wl_dpy = disp->PlatformDisplay;
767 }
768
769 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
770 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
771 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
772 dri2_dpy->wl_queue);
773 wl_registry_add_listener(dri2_dpy->wl_registry,
774 &registry_listener, dri2_dpy);
775 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
776 goto cleanup_dpy;
777
778 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
779 goto cleanup_drm;
780
781 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
782 goto cleanup_fd;
783
784 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
785 if (dri2_dpy->driver_name == NULL) {
786 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
787 goto cleanup_fd;
788 }
789
790 if (!dri2_load_driver(disp))
791 goto cleanup_driver_name;
792
793 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
794 dri2_dpy->dri2_loader_extension.base.version = 3;
795 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
796 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
797 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
798 dri2_get_buffers_with_format;
799
800 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
801 dri2_dpy->extensions[1] = &image_lookup_extension.base;
802 dri2_dpy->extensions[2] = &use_invalidate.base;
803 dri2_dpy->extensions[3] = NULL;
804
805 if (!dri2_create_screen(disp))
806 goto cleanup_driver;
807
808 types = EGL_WINDOW_BIT;
809 for (i = 0; dri2_dpy->driver_configs[i]; i++) {
810 config = dri2_dpy->driver_configs[i];
811 if (dri2_dpy->formats & HAS_XRGB8888)
812 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks);
813 if (dri2_dpy->formats & HAS_ARGB8888)
814 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks);
815 }
816
817 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
818 dri2_dpy->authenticate = dri2_wayland_authenticate;
819
820 /* we're supporting EGL 1.4 */
821 disp->VersionMajor = 1;
822 disp->VersionMinor = 4;
823
824 return EGL_TRUE;
825
826 cleanup_driver:
827 dlclose(dri2_dpy->driver);
828 cleanup_driver_name:
829 free(dri2_dpy->driver_name);
830 cleanup_fd:
831 close(dri2_dpy->fd);
832 cleanup_drm:
833 free(dri2_dpy->device_name);
834 wl_drm_destroy(dri2_dpy->wl_drm);
835 cleanup_dpy:
836 free(dri2_dpy);
837
838 return EGL_FALSE;
839 }