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