egl/wayland: Don't invalidate drawable on swap 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 if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
424 (dri2_surf->base.Width != dri2_surf->wl_win->width ||
425 dri2_surf->base.Height != dri2_surf->wl_win->height)) {
426
427 dri2_release_buffers(dri2_surf);
428
429 dri2_surf->base.Width = dri2_surf->wl_win->width;
430 dri2_surf->base.Height = dri2_surf->wl_win->height;
431 dri2_surf->dx = dri2_surf->wl_win->dx;
432 dri2_surf->dy = dri2_surf->wl_win->dy;
433
434 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
435 if (dri2_surf->wl_drm_buffer[i])
436 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
437 dri2_surf->wl_drm_buffer[i] = NULL;
438 dri2_surf->wl_buffer_lock[i] = 0;
439 }
440 }
441
442 dri2_surf->buffer_count = 0;
443 for (i = 0; i < 2*count; i+=2) {
444 assert(attachments[i] < __DRI_BUFFER_COUNT);
445 assert(dri2_surf->buffer_count < 5);
446
447 dri2_prior_buffer_creation(dri2_surf, attachments[i]);
448
449 if (dri2_surf->dri_buffers[attachments[i]] == NULL) {
450
451 dri2_surf->dri_buffers[attachments[i]] =
452 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
453 attachments[i], attachments[i+1],
454 dri2_surf->base.Width, dri2_surf->base.Height);
455
456 if (!dri2_surf->dri_buffers[attachments[i]])
457 continue;
458
459 if (attachments[i] == __DRI_BUFFER_BACK_LEFT)
460 dri2_process_back_buffer(dri2_surf, attachments[i+1]);
461 }
462
463 memcpy(&dri2_surf->buffers[dri2_surf->buffer_count],
464 dri2_surf->dri_buffers[attachments[i]],
465 sizeof(__DRIbuffer));
466
467 dri2_surf->buffer_count++;
468 }
469
470 assert(dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
471
472 *out_count = dri2_surf->buffer_count;
473 if (dri2_surf->buffer_count == 0)
474 return NULL;
475
476 *width = dri2_surf->base.Width;
477 *height = dri2_surf->base.Height;
478
479 return dri2_surf->buffers;
480 }
481
482 static __DRIbuffer *
483 dri2_get_buffers(__DRIdrawable * driDrawable,
484 int *width, int *height,
485 unsigned int *attachments, int count,
486 int *out_count, void *loaderPrivate)
487 {
488 unsigned int *attachments_with_format;
489 __DRIbuffer *buffer;
490 const unsigned int format = 32;
491 int i;
492
493 attachments_with_format = calloc(count * 2, sizeof(unsigned int));
494 if (!attachments_with_format) {
495 *out_count = 0;
496 return NULL;
497 }
498
499 for (i = 0; i < count; ++i) {
500 attachments_with_format[2*i] = attachments[i];
501 attachments_with_format[2*i + 1] = format;
502 }
503
504 buffer =
505 dri2_get_buffers_with_format(driDrawable,
506 width, height,
507 attachments_with_format, count,
508 out_count, loaderPrivate);
509
510 free(attachments_with_format);
511
512 return buffer;
513 }
514
515
516 static void
517 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
518 {
519 (void) driDrawable;
520
521 /* FIXME: Does EGL support front buffer rendering at all? */
522
523 #if 0
524 struct dri2_egl_surface *dri2_surf = loaderPrivate;
525
526 dri2WaitGL(dri2_surf);
527 #else
528 (void) loaderPrivate;
529 #endif
530 }
531
532 static void
533 wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
534 {
535 struct dri2_egl_surface *dri2_surf = data;
536
537 dri2_surf->frame_callback = NULL;
538 wl_callback_destroy(callback);
539 }
540
541 static const struct wl_callback_listener frame_listener = {
542 wayland_frame_callback
543 };
544
545 /**
546 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
547 */
548 static EGLBoolean
549 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
550 {
551 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
552 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
553 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
554 int ret = 0;
555
556 while (dri2_surf->frame_callback && ret != -1)
557 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
558 if (ret < 0)
559 return EGL_FALSE;
560
561 dri2_surf->frame_callback = wl_surface_frame(dri2_surf->wl_win->surface);
562 wl_callback_add_listener(dri2_surf->frame_callback,
563 &frame_listener, dri2_surf);
564 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->frame_callback,
565 dri2_dpy->wl_queue);
566
567 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
568 pointer_swap(
569 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
570 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
571
572 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment =
573 __DRI_BUFFER_FRONT_LEFT;
574 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment =
575 __DRI_BUFFER_BACK_LEFT;
576
577 swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK);
578
579 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT])
580 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] =
581 wayland_create_buffer(dri2_surf,
582 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]);
583
584 wl_surface_attach(dri2_surf->wl_win->surface,
585 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
586 dri2_surf->dx, dri2_surf->dy);
587 dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1;
588
589 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
590 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
591 /* reset resize growing parameters */
592 dri2_surf->dx = 0;
593 dri2_surf->dy = 0;
594
595 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
596 dri2_surf->base.Width, dri2_surf->base.Height);
597
598 wl_surface_commit(dri2_surf->wl_win->surface);
599 }
600
601 _EGLContext *ctx;
602 if (dri2_drv->glFlush) {
603 ctx = _eglGetCurrentContext();
604 if (ctx && ctx->DrawSurface == &dri2_surf->base)
605 dri2_drv->glFlush();
606 }
607
608 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
609
610 return EGL_TRUE;
611 }
612
613 static int
614 dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
615 {
616 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
617 int ret = 0;
618
619 dri2_dpy->authenticated = 0;
620
621 wl_drm_authenticate(dri2_dpy->wl_drm, id);
622 if (roundtrip(dri2_dpy) < 0)
623 ret = -1;
624
625 if (!dri2_dpy->authenticated)
626 ret = -1;
627
628 /* reset authenticated */
629 dri2_dpy->authenticated = 1;
630
631 return ret;
632 }
633
634 /**
635 * Called via eglTerminate(), drv->API.Terminate().
636 */
637 static EGLBoolean
638 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
639 {
640 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
641
642 _eglReleaseDisplayResources(drv, disp);
643 _eglCleanupDisplay(disp);
644
645 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
646 close(dri2_dpy->fd);
647 dlclose(dri2_dpy->driver);
648 free(dri2_dpy->driver_name);
649 free(dri2_dpy->device_name);
650 wl_drm_destroy(dri2_dpy->wl_drm);
651 if (dri2_dpy->own_device)
652 wl_display_disconnect(dri2_dpy->wl_dpy);
653 free(dri2_dpy);
654 disp->DriverData = NULL;
655
656 return EGL_TRUE;
657 }
658
659 static void
660 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
661 {
662 struct dri2_egl_display *dri2_dpy = data;
663 drm_magic_t magic;
664
665 dri2_dpy->device_name = strdup(device);
666 if (!dri2_dpy->device_name)
667 return;
668
669 #ifdef O_CLOEXEC
670 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
671 if (dri2_dpy->fd == -1 && errno == EINVAL)
672 #endif
673 {
674 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
675 if (dri2_dpy->fd != -1)
676 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
677 FD_CLOEXEC);
678 }
679 if (dri2_dpy->fd == -1) {
680 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
681 dri2_dpy->device_name, strerror(errno));
682 return;
683 }
684
685 drmGetMagic(dri2_dpy->fd, &magic);
686 wl_drm_authenticate(dri2_dpy->wl_drm, magic);
687 }
688
689 static void
690 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
691 {
692 struct dri2_egl_display *dri2_dpy = data;
693
694 switch (format) {
695 case WL_DRM_FORMAT_ARGB8888:
696 dri2_dpy->formats |= HAS_ARGB8888;
697 break;
698 case WL_DRM_FORMAT_XRGB8888:
699 dri2_dpy->formats |= HAS_XRGB8888;
700 break;
701 }
702 }
703
704 static void
705 drm_handle_authenticated(void *data, struct wl_drm *drm)
706 {
707 struct dri2_egl_display *dri2_dpy = data;
708
709 dri2_dpy->authenticated = 1;
710 }
711
712 static const struct wl_drm_listener drm_listener = {
713 drm_handle_device,
714 drm_handle_format,
715 drm_handle_authenticated
716 };
717
718 static void
719 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
720 const char *interface, uint32_t version)
721 {
722 struct dri2_egl_display *dri2_dpy = data;
723
724 if (strcmp(interface, "wl_drm") == 0) {
725 dri2_dpy->wl_drm =
726 wl_registry_bind(registry, name, &wl_drm_interface, 1);
727 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
728 }
729 }
730
731 static const struct wl_registry_listener registry_listener = {
732 registry_handle_global
733 };
734
735 EGLBoolean
736 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
737 {
738 struct dri2_egl_display *dri2_dpy;
739 const __DRIconfig *config;
740 uint32_t types;
741 int i;
742 static const unsigned int argb_masks[4] =
743 { 0xff0000, 0xff00, 0xff, 0xff000000 };
744 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
745
746 drv->API.CreateWindowSurface = dri2_create_window_surface;
747 drv->API.DestroySurface = dri2_destroy_surface;
748 drv->API.SwapBuffers = dri2_swap_buffers;
749 drv->API.Terminate = dri2_terminate;
750
751 dri2_dpy = calloc(1, sizeof *dri2_dpy);
752 if (!dri2_dpy)
753 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
754
755 disp->DriverData = (void *) dri2_dpy;
756 if (disp->PlatformDisplay == NULL) {
757 dri2_dpy->wl_dpy = wl_display_connect(NULL);
758 if (dri2_dpy->wl_dpy == NULL)
759 goto cleanup_dpy;
760 dri2_dpy->own_device = 1;
761 } else {
762 dri2_dpy->wl_dpy = disp->PlatformDisplay;
763 }
764
765 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
766 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
767 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
768 dri2_dpy->wl_queue);
769 wl_registry_add_listener(dri2_dpy->wl_registry,
770 &registry_listener, dri2_dpy);
771 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
772 goto cleanup_dpy;
773
774 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
775 goto cleanup_drm;
776
777 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
778 goto cleanup_fd;
779
780 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
781 if (dri2_dpy->driver_name == NULL) {
782 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
783 goto cleanup_fd;
784 }
785
786 if (!dri2_load_driver(disp))
787 goto cleanup_driver_name;
788
789 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
790 dri2_dpy->dri2_loader_extension.base.version = 3;
791 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
792 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
793 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
794 dri2_get_buffers_with_format;
795
796 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
797 dri2_dpy->extensions[1] = &image_lookup_extension.base;
798 dri2_dpy->extensions[2] = &use_invalidate.base;
799 dri2_dpy->extensions[3] = NULL;
800
801 if (!dri2_create_screen(disp))
802 goto cleanup_driver;
803
804 types = EGL_WINDOW_BIT;
805 for (i = 0; dri2_dpy->driver_configs[i]; i++) {
806 config = dri2_dpy->driver_configs[i];
807 if (dri2_dpy->formats & HAS_XRGB8888)
808 dri2_add_config(disp, config, i + 1, 0, types, NULL, rgb_masks);
809 if (dri2_dpy->formats & HAS_ARGB8888)
810 dri2_add_config(disp, config, i + 1, 0, types, NULL, argb_masks);
811 }
812
813 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
814 dri2_dpy->authenticate = dri2_wayland_authenticate;
815
816 /* we're supporting EGL 1.4 */
817 disp->VersionMajor = 1;
818 disp->VersionMinor = 4;
819
820 return EGL_TRUE;
821
822 cleanup_driver:
823 dlclose(dri2_dpy->driver);
824 cleanup_driver_name:
825 free(dri2_dpy->driver_name);
826 cleanup_fd:
827 close(dri2_dpy->fd);
828 cleanup_drm:
829 free(dri2_dpy->device_name);
830 wl_drm_destroy(dri2_dpy->wl_drm);
831 cleanup_dpy:
832 free(dri2_dpy);
833
834 return EGL_FALSE;
835 }