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