egl_dri2: use loader util lib
[mesa.git] / src / egl / drivers / dri2 / platform_wayland.c
1 /*
2 * Copyright © 2011-2012 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 #include "loader.h"
40
41 #include <wayland-client.h>
42 #include "wayland-drm-client-protocol.h"
43
44 enum wl_drm_format_flags {
45 HAS_ARGB8888 = 1,
46 HAS_XRGB8888 = 2,
47 HAS_RGB565 = 4,
48 };
49
50 static void
51 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
52 {
53 int *done = data;
54
55 *done = 1;
56 wl_callback_destroy(callback);
57 }
58
59 static const struct wl_callback_listener sync_listener = {
60 sync_callback
61 };
62
63 static int
64 roundtrip(struct dri2_egl_display *dri2_dpy)
65 {
66 struct wl_callback *callback;
67 int done = 0, ret = 0;
68
69 callback = wl_display_sync(dri2_dpy->wl_dpy);
70 wl_callback_add_listener(callback, &sync_listener, &done);
71 wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue);
72 while (ret != -1 && !done)
73 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
74
75 if (!done)
76 wl_callback_destroy(callback);
77
78 return ret;
79 }
80
81 static void
82 wl_buffer_release(void *data, struct wl_buffer *buffer)
83 {
84 struct dri2_egl_surface *dri2_surf = data;
85 int i;
86
87 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
88 if (dri2_surf->color_buffers[i].wl_buffer == buffer)
89 break;
90
91 if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
92 wl_buffer_destroy(buffer);
93 return;
94 }
95
96 dri2_surf->color_buffers[i].locked = 0;
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
125 (void) drv;
126
127 dri2_surf = malloc(sizeof *dri2_surf);
128 if (!dri2_surf) {
129 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
130 return NULL;
131 }
132
133 memset(dri2_surf, 0, sizeof *dri2_surf);
134 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
135 goto cleanup_surf;
136
137 if (conf->RedSize == 5)
138 dri2_surf->format = WL_DRM_FORMAT_RGB565;
139 else if (conf->AlphaSize == 0)
140 dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
141 else
142 dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
143
144 switch (type) {
145 case EGL_WINDOW_BIT:
146 dri2_surf->wl_win = (struct wl_egl_window *) window;
147
148 dri2_surf->wl_win->private = dri2_surf;
149 dri2_surf->wl_win->resize_callback = resize_callback;
150
151 dri2_surf->base.Width = -1;
152 dri2_surf->base.Height = -1;
153 break;
154 default:
155 goto cleanup_surf;
156 }
157
158 dri2_surf->dri_drawable =
159 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
160 type == EGL_WINDOW_BIT ?
161 dri2_conf->dri_double_config :
162 dri2_conf->dri_single_config,
163 dri2_surf);
164 if (dri2_surf->dri_drawable == NULL) {
165 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
166 goto cleanup_dri_drawable;
167 }
168
169 return &dri2_surf->base;
170
171 cleanup_dri_drawable:
172 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
173 cleanup_surf:
174 free(dri2_surf);
175
176 return NULL;
177 }
178
179 /**
180 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
181 */
182 static _EGLSurface *
183 dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
184 _EGLConfig *conf, EGLNativeWindowType window,
185 const EGLint *attrib_list)
186 {
187 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
188 _EGLSurface *surf;
189
190 surf = dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
191 window, attrib_list);
192
193 if (surf != NULL)
194 drv->API.SwapInterval(drv, disp, surf, dri2_dpy->default_swap_interval);
195
196 return surf;
197 }
198
199 /**
200 * Called via eglDestroySurface(), drv->API.DestroySurface().
201 */
202 static EGLBoolean
203 dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
204 {
205 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
206 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
207 int i;
208
209 (void) drv;
210
211 if (!_eglPutSurface(surf))
212 return EGL_TRUE;
213
214 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
215
216 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
217 if (dri2_surf->color_buffers[i].wl_buffer)
218 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
219 if (dri2_surf->color_buffers[i].dri_image)
220 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
221 }
222
223 for (i = 0; i < __DRI_BUFFER_COUNT; i++)
224 if (dri2_surf->dri_buffers[i] &&
225 dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
226 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
227 dri2_surf->dri_buffers[i]);
228
229 if (dri2_surf->throttle_callback)
230 wl_callback_destroy(dri2_surf->throttle_callback);
231
232 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
233 dri2_surf->wl_win->private = NULL;
234 dri2_surf->wl_win->resize_callback = NULL;
235 }
236
237 free(surf);
238
239 return EGL_TRUE;
240 }
241
242 static void
243 dri2_release_buffers(struct dri2_egl_surface *dri2_surf)
244 {
245 struct dri2_egl_display *dri2_dpy =
246 dri2_egl_display(dri2_surf->base.Resource.Display);
247 int i;
248
249 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
250 if (dri2_surf->color_buffers[i].wl_buffer &&
251 !dri2_surf->color_buffers[i].locked)
252 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
253 if (dri2_surf->color_buffers[i].dri_image)
254 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
255
256 dri2_surf->color_buffers[i].wl_buffer = NULL;
257 dri2_surf->color_buffers[i].dri_image = NULL;
258 dri2_surf->color_buffers[i].locked = 0;
259 }
260
261 for (i = 0; i < __DRI_BUFFER_COUNT; i++)
262 if (dri2_surf->dri_buffers[i] &&
263 dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
264 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
265 dri2_surf->dri_buffers[i]);
266 }
267
268 static int
269 get_back_bo(struct dri2_egl_surface *dri2_surf)
270 {
271 struct dri2_egl_display *dri2_dpy =
272 dri2_egl_display(dri2_surf->base.Resource.Display);
273 int i;
274
275 /* We always want to throttle to some event (either a frame callback or
276 * a sync request) after the commit so that we can be sure the
277 * compositor has had a chance to handle it and send us a release event
278 * before we look for a free buffer */
279 while (dri2_surf->throttle_callback != NULL)
280 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
281 dri2_dpy->wl_queue) == -1)
282 return -1;
283
284 if (dri2_surf->back == NULL) {
285 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
286 /* Get an unlocked buffer, preferrably one with a dri_buffer
287 * already allocated. */
288 if (dri2_surf->color_buffers[i].locked)
289 continue;
290 if (dri2_surf->back == NULL)
291 dri2_surf->back = &dri2_surf->color_buffers[i];
292 else if (dri2_surf->back->dri_image == NULL)
293 dri2_surf->back = &dri2_surf->color_buffers[i];
294 }
295 }
296
297 if (dri2_surf->back == NULL)
298 return -1;
299 if (dri2_surf->back->dri_image == NULL) {
300 dri2_surf->back->dri_image =
301 dri2_dpy->image->createImage(dri2_dpy->dri_screen,
302 dri2_surf->base.Width,
303 dri2_surf->base.Height,
304 __DRI_IMAGE_FORMAT_ARGB8888,
305 __DRI_IMAGE_USE_SHARE,
306 NULL);
307 dri2_surf->back->age = 0;
308 }
309 if (dri2_surf->back->dri_image == NULL)
310 return -1;
311
312 dri2_surf->back->locked = 1;
313
314 return 0;
315 }
316
317
318 static void
319 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
320 {
321 struct dri2_egl_display *dri2_dpy =
322 dri2_egl_display(dri2_surf->base.Resource.Display);
323 __DRIimage *image;
324 int name, pitch;
325
326 image = dri2_surf->back->dri_image;
327
328 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
329 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
330
331 buffer->attachment = __DRI_BUFFER_BACK_LEFT;
332 buffer->name = name;
333 buffer->pitch = pitch;
334 buffer->cpp = 4;
335 buffer->flags = 0;
336 }
337
338 static int
339 get_aux_bo(struct dri2_egl_surface *dri2_surf,
340 unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
341 {
342 struct dri2_egl_display *dri2_dpy =
343 dri2_egl_display(dri2_surf->base.Resource.Display);
344 __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
345
346 if (b == NULL) {
347 b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
348 attachment, format,
349 dri2_surf->base.Width,
350 dri2_surf->base.Height);
351 dri2_surf->dri_buffers[attachment] = b;
352 }
353 if (b == NULL)
354 return -1;
355
356 memcpy(buffer, b, sizeof *buffer);
357
358 return 0;
359 }
360
361 static int
362 update_buffers(struct dri2_egl_surface *dri2_surf)
363 {
364 struct dri2_egl_display *dri2_dpy =
365 dri2_egl_display(dri2_surf->base.Resource.Display);
366 int i;
367
368 if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
369 (dri2_surf->base.Width != dri2_surf->wl_win->width ||
370 dri2_surf->base.Height != dri2_surf->wl_win->height)) {
371
372 dri2_release_buffers(dri2_surf);
373
374 dri2_surf->base.Width = dri2_surf->wl_win->width;
375 dri2_surf->base.Height = dri2_surf->wl_win->height;
376 dri2_surf->dx = dri2_surf->wl_win->dx;
377 dri2_surf->dy = dri2_surf->wl_win->dy;
378 }
379
380 if (get_back_bo(dri2_surf) < 0) {
381 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
382 return -1;
383 }
384
385 /* If we have an extra unlocked buffer at this point, we had to do triple
386 * buffering for a while, but now can go back to just double buffering.
387 * That means we can free any unlocked buffer now. */
388 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
389 if (!dri2_surf->color_buffers[i].locked &&
390 dri2_surf->color_buffers[i].wl_buffer) {
391 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
392 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
393 dri2_surf->color_buffers[i].wl_buffer = NULL;
394 dri2_surf->color_buffers[i].dri_image = NULL;
395 }
396 }
397
398 return 0;
399 }
400
401 static __DRIbuffer *
402 dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
403 int *width, int *height,
404 unsigned int *attachments, int count,
405 int *out_count, void *loaderPrivate)
406 {
407 struct dri2_egl_surface *dri2_surf = loaderPrivate;
408 int i, j;
409
410 if (update_buffers(dri2_surf) < 0)
411 return NULL;
412
413 for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
414 switch (attachments[i]) {
415 case __DRI_BUFFER_BACK_LEFT:
416 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
417 break;
418 default:
419 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
420 &dri2_surf->buffers[j]) < 0) {
421 _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
422 return NULL;
423 }
424 break;
425 }
426 }
427
428 *out_count = j;
429 if (j == 0)
430 return NULL;
431
432 *width = dri2_surf->base.Width;
433 *height = dri2_surf->base.Height;
434
435 return dri2_surf->buffers;
436 }
437
438 static __DRIbuffer *
439 dri2_get_buffers(__DRIdrawable * driDrawable,
440 int *width, int *height,
441 unsigned int *attachments, int count,
442 int *out_count, void *loaderPrivate)
443 {
444 unsigned int *attachments_with_format;
445 __DRIbuffer *buffer;
446 const unsigned int format = 32;
447 int i;
448
449 attachments_with_format = calloc(count * 2, sizeof(unsigned int));
450 if (!attachments_with_format) {
451 *out_count = 0;
452 return NULL;
453 }
454
455 for (i = 0; i < count; ++i) {
456 attachments_with_format[2*i] = attachments[i];
457 attachments_with_format[2*i + 1] = format;
458 }
459
460 buffer =
461 dri2_get_buffers_with_format(driDrawable,
462 width, height,
463 attachments_with_format, count,
464 out_count, loaderPrivate);
465
466 free(attachments_with_format);
467
468 return buffer;
469 }
470
471 static int
472 image_get_buffers(__DRIdrawable *driDrawable,
473 unsigned int format,
474 uint32_t *stamp,
475 void *loaderPrivate,
476 uint32_t buffer_mask,
477 struct __DRIimageList *buffers)
478 {
479 struct dri2_egl_surface *dri2_surf = loaderPrivate;
480
481 if (update_buffers(dri2_surf) < 0)
482 return 0;
483
484 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
485 buffers->back = dri2_surf->back->dri_image;
486
487 return 1;
488 }
489
490 static void
491 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
492 {
493 (void) driDrawable;
494 (void) loaderPrivate;
495 }
496
497 static const __DRIimageLoaderExtension image_loader_extension = {
498 { __DRI_IMAGE_LOADER, 1 },
499 image_get_buffers,
500 dri2_flush_front_buffer
501 };
502
503 static void
504 wayland_throttle_callback(void *data,
505 struct wl_callback *callback,
506 uint32_t time)
507 {
508 struct dri2_egl_surface *dri2_surf = data;
509
510 dri2_surf->throttle_callback = NULL;
511 wl_callback_destroy(callback);
512 }
513
514 static const struct wl_callback_listener throttle_listener = {
515 wayland_throttle_callback
516 };
517
518 static void
519 create_wl_buffer(struct dri2_egl_surface *dri2_surf)
520 {
521 struct dri2_egl_display *dri2_dpy =
522 dri2_egl_display(dri2_surf->base.Resource.Display);
523 int fd, stride, name;
524
525 if (dri2_surf->current->wl_buffer != NULL)
526 return;
527
528 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
529 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
530 __DRI_IMAGE_ATTRIB_FD, &fd);
531 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
532 __DRI_IMAGE_ATTRIB_STRIDE, &stride);
533
534 dri2_surf->current->wl_buffer =
535 wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
536 fd,
537 dri2_surf->base.Width,
538 dri2_surf->base.Height,
539 dri2_surf->format,
540 0, stride,
541 0, 0,
542 0, 0);
543 close(fd);
544 } else {
545 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
546 __DRI_IMAGE_ATTRIB_NAME, &name);
547 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
548 __DRI_IMAGE_ATTRIB_STRIDE, &stride);
549
550 dri2_surf->current->wl_buffer =
551 wl_drm_create_buffer(dri2_dpy->wl_drm,
552 name,
553 dri2_surf->base.Width,
554 dri2_surf->base.Height,
555 stride,
556 dri2_surf->format);
557 }
558
559 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer,
560 dri2_dpy->wl_queue);
561 wl_buffer_add_listener(dri2_surf->current->wl_buffer,
562 &wl_buffer_listener, dri2_surf);
563 }
564
565 /**
566 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
567 */
568 static EGLBoolean
569 dri2_swap_buffers_with_damage(_EGLDriver *drv,
570 _EGLDisplay *disp,
571 _EGLSurface *draw,
572 const EGLint *rects,
573 EGLint n_rects)
574 {
575 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
576 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
577 struct dri2_egl_context *dri2_ctx;
578 _EGLContext *ctx;
579 int i;
580
581 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
582 if (dri2_surf->color_buffers[i].age > 0)
583 dri2_surf->color_buffers[i].age++;
584
585 /* Make sure we have a back buffer in case we're swapping without ever
586 * rendering. */
587 if (get_back_bo(dri2_surf) < 0) {
588 _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
589 return EGL_FALSE;
590 }
591
592 if (draw->SwapInterval > 0) {
593 dri2_surf->throttle_callback =
594 wl_surface_frame(dri2_surf->wl_win->surface);
595 wl_callback_add_listener(dri2_surf->throttle_callback,
596 &throttle_listener, dri2_surf);
597 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
598 dri2_dpy->wl_queue);
599 }
600
601 dri2_surf->back->age = 1;
602 dri2_surf->current = dri2_surf->back;
603 dri2_surf->back = NULL;
604
605 create_wl_buffer(dri2_surf);
606
607 wl_surface_attach(dri2_surf->wl_win->surface,
608 dri2_surf->current->wl_buffer,
609 dri2_surf->dx, dri2_surf->dy);
610
611 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
612 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
613 /* reset resize growing parameters */
614 dri2_surf->dx = 0;
615 dri2_surf->dy = 0;
616
617 if (n_rects == 0) {
618 wl_surface_damage(dri2_surf->wl_win->surface,
619 0, 0, INT32_MAX, INT32_MAX);
620 } else {
621 for (i = 0; i < n_rects; i++) {
622 const int *rect = &rects[i * 4];
623 wl_surface_damage(dri2_surf->wl_win->surface,
624 rect[0],
625 dri2_surf->base.Height - rect[1] - rect[3],
626 rect[2], rect[3]);
627 }
628 }
629
630 if (dri2_dpy->flush->base.version >= 4) {
631 ctx = _eglGetCurrentContext();
632 dri2_ctx = dri2_egl_context(ctx);
633 (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context,
634 dri2_surf->dri_drawable,
635 __DRI2_FLUSH_DRAWABLE,
636 __DRI2_THROTTLE_SWAPBUFFER);
637 } else {
638 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
639 }
640
641 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
642
643 wl_surface_commit(dri2_surf->wl_win->surface);
644
645 /* If we're not waiting for a frame callback then we'll at least throttle
646 * to a sync callback so that we always give a chance for the compositor to
647 * handle the commit and send a release event before checking for a free
648 * buffer */
649 if (dri2_surf->throttle_callback == NULL) {
650 dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
651 wl_callback_add_listener(dri2_surf->throttle_callback,
652 &throttle_listener, dri2_surf);
653 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
654 dri2_dpy->wl_queue);
655 }
656
657 wl_display_flush(dri2_dpy->wl_dpy);
658
659 return EGL_TRUE;
660 }
661
662 static EGLint
663 dri2_query_buffer_age(_EGLDriver *drv,
664 _EGLDisplay *disp, _EGLSurface *surface)
665 {
666 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
667
668 if (get_back_bo(dri2_surf) < 0) {
669 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
670 return 0;
671 }
672
673 return dri2_surf->back->age;
674 }
675
676 static EGLBoolean
677 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
678 {
679 return dri2_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
680 }
681
682 static struct wl_buffer *
683 dri2_create_wayland_buffer_from_image_wl(_EGLDriver *drv,
684 _EGLDisplay *disp,
685 _EGLImage *img)
686 {
687 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
688 struct dri2_egl_image *dri2_img = dri2_egl_image(img);
689 __DRIimage *image = dri2_img->dri_image;
690 struct wl_buffer *buffer;
691 int width, height, format, pitch;
692 enum wl_drm_format wl_format;
693
694 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
695
696 switch (format) {
697 case __DRI_IMAGE_FORMAT_ARGB8888:
698 if (!(dri2_dpy->formats & HAS_ARGB8888))
699 goto bad_format;
700 wl_format = WL_DRM_FORMAT_ARGB8888;
701 break;
702 case __DRI_IMAGE_FORMAT_XRGB8888:
703 if (!(dri2_dpy->formats & HAS_XRGB8888))
704 goto bad_format;
705 wl_format = WL_DRM_FORMAT_XRGB8888;
706 break;
707 default:
708 goto bad_format;
709 }
710
711 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
712 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
713 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
714
715 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
716 int fd;
717
718 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
719
720 buffer =
721 wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
722 fd,
723 width, height,
724 wl_format,
725 0, pitch,
726 0, 0,
727 0, 0);
728
729 close(fd);
730 } else {
731 int name;
732
733 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
734
735 buffer =
736 wl_drm_create_buffer(dri2_dpy->wl_drm,
737 name,
738 width, height,
739 pitch,
740 wl_format);
741 }
742
743 /* The buffer object will have been created with our internal event queue
744 * because it is using the wl_drm object as a proxy factory. We want the
745 * buffer to be used by the application so we'll reset it to the display's
746 * default event queue */
747 if (buffer)
748 wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
749
750 return buffer;
751
752 bad_format:
753 _eglError(EGL_BAD_MATCH, "unsupported image format");
754 return NULL;
755 }
756
757 static int
758 dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
759 {
760 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
761 int ret = 0;
762
763 dri2_dpy->authenticated = 0;
764
765 wl_drm_authenticate(dri2_dpy->wl_drm, id);
766 if (roundtrip(dri2_dpy) < 0)
767 ret = -1;
768
769 if (!dri2_dpy->authenticated)
770 ret = -1;
771
772 /* reset authenticated */
773 dri2_dpy->authenticated = 1;
774
775 return ret;
776 }
777
778 /**
779 * Called via eglTerminate(), drv->API.Terminate().
780 */
781 static EGLBoolean
782 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
783 {
784 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
785
786 _eglReleaseDisplayResources(drv, disp);
787 _eglCleanupDisplay(disp);
788
789 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
790 close(dri2_dpy->fd);
791 dlclose(dri2_dpy->driver);
792 free(dri2_dpy->driver_name);
793 free(dri2_dpy->device_name);
794 wl_drm_destroy(dri2_dpy->wl_drm);
795 if (dri2_dpy->own_device)
796 wl_display_disconnect(dri2_dpy->wl_dpy);
797 free(dri2_dpy);
798 disp->DriverData = NULL;
799
800 return EGL_TRUE;
801 }
802
803 static void
804 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
805 {
806 struct dri2_egl_display *dri2_dpy = data;
807 drm_magic_t magic;
808
809 dri2_dpy->device_name = strdup(device);
810 if (!dri2_dpy->device_name)
811 return;
812
813 #ifdef O_CLOEXEC
814 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
815 if (dri2_dpy->fd == -1 && errno == EINVAL)
816 #endif
817 {
818 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
819 if (dri2_dpy->fd != -1)
820 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
821 FD_CLOEXEC);
822 }
823 if (dri2_dpy->fd == -1) {
824 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
825 dri2_dpy->device_name, strerror(errno));
826 return;
827 }
828
829 drmGetMagic(dri2_dpy->fd, &magic);
830 wl_drm_authenticate(dri2_dpy->wl_drm, magic);
831 }
832
833 static void
834 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
835 {
836 struct dri2_egl_display *dri2_dpy = data;
837
838 switch (format) {
839 case WL_DRM_FORMAT_ARGB8888:
840 dri2_dpy->formats |= HAS_ARGB8888;
841 break;
842 case WL_DRM_FORMAT_XRGB8888:
843 dri2_dpy->formats |= HAS_XRGB8888;
844 break;
845 case WL_DRM_FORMAT_RGB565:
846 dri2_dpy->formats |= HAS_RGB565;
847 break;
848 }
849 }
850
851 static void
852 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
853 {
854 struct dri2_egl_display *dri2_dpy = data;
855
856 dri2_dpy->capabilities = value;
857 }
858
859 static void
860 drm_handle_authenticated(void *data, struct wl_drm *drm)
861 {
862 struct dri2_egl_display *dri2_dpy = data;
863
864 dri2_dpy->authenticated = 1;
865 }
866
867 static const struct wl_drm_listener drm_listener = {
868 drm_handle_device,
869 drm_handle_format,
870 drm_handle_authenticated,
871 drm_handle_capabilities
872 };
873
874 static void
875 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
876 const char *interface, uint32_t version)
877 {
878 struct dri2_egl_display *dri2_dpy = data;
879
880 if (version > 1)
881 version = 2;
882 if (strcmp(interface, "wl_drm") == 0) {
883 dri2_dpy->wl_drm =
884 wl_registry_bind(registry, name, &wl_drm_interface, version);
885 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
886 }
887 }
888
889 static void
890 registry_handle_global_remove(void *data, struct wl_registry *registry,
891 uint32_t name)
892 {
893 }
894
895 static const struct wl_registry_listener registry_listener = {
896 registry_handle_global,
897 registry_handle_global_remove
898 };
899
900 static EGLBoolean
901 dri2_swap_interval(_EGLDriver *drv,
902 _EGLDisplay *disp,
903 _EGLSurface *surf,
904 EGLint interval)
905 {
906 if (interval > surf->Config->MaxSwapInterval)
907 interval = surf->Config->MaxSwapInterval;
908 else if (interval < surf->Config->MinSwapInterval)
909 interval = surf->Config->MinSwapInterval;
910
911 surf->SwapInterval = interval;
912
913 return EGL_TRUE;
914 }
915
916 static void
917 dri2_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
918 {
919 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
920
921 /* We can't use values greater than 1 on Wayland because we are using the
922 * frame callback to synchronise the frame and the only way we be sure to
923 * get a frame callback is to attach a new buffer. Therefore we can't just
924 * sit drawing nothing to wait until the next ‘n’ frame callbacks */
925
926 if (dri2_dpy->config)
927 dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
928 "vblank_mode", &vblank_mode);
929 switch (vblank_mode) {
930 case DRI_CONF_VBLANK_NEVER:
931 dri2_dpy->min_swap_interval = 0;
932 dri2_dpy->max_swap_interval = 0;
933 dri2_dpy->default_swap_interval = 0;
934 break;
935 case DRI_CONF_VBLANK_ALWAYS_SYNC:
936 dri2_dpy->min_swap_interval = 1;
937 dri2_dpy->max_swap_interval = 1;
938 dri2_dpy->default_swap_interval = 1;
939 break;
940 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
941 dri2_dpy->min_swap_interval = 0;
942 dri2_dpy->max_swap_interval = 1;
943 dri2_dpy->default_swap_interval = 0;
944 break;
945 default:
946 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
947 dri2_dpy->min_swap_interval = 0;
948 dri2_dpy->max_swap_interval = 1;
949 dri2_dpy->default_swap_interval = 1;
950 break;
951 }
952 }
953
954 EGLBoolean
955 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
956 {
957 struct dri2_egl_display *dri2_dpy;
958 const __DRIconfig *config;
959 uint32_t types;
960 int i;
961 static const unsigned int argb_masks[4] =
962 { 0xff0000, 0xff00, 0xff, 0xff000000 };
963 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
964 static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 };
965
966 loader_set_logger(_eglLog);
967
968 drv->API.CreateWindowSurface = dri2_create_window_surface;
969 drv->API.DestroySurface = dri2_destroy_surface;
970 drv->API.SwapBuffers = dri2_swap_buffers;
971 drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
972 drv->API.SwapInterval = dri2_swap_interval;
973 drv->API.Terminate = dri2_terminate;
974 drv->API.QueryBufferAge = dri2_query_buffer_age;
975
976 drv->API.CreateWaylandBufferFromImageWL =
977 dri2_create_wayland_buffer_from_image_wl;
978
979 dri2_dpy = calloc(1, sizeof *dri2_dpy);
980 if (!dri2_dpy)
981 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
982
983 disp->DriverData = (void *) dri2_dpy;
984 if (disp->PlatformDisplay == NULL) {
985 dri2_dpy->wl_dpy = wl_display_connect(NULL);
986 if (dri2_dpy->wl_dpy == NULL)
987 goto cleanup_dpy;
988 dri2_dpy->own_device = 1;
989 } else {
990 dri2_dpy->wl_dpy = disp->PlatformDisplay;
991 }
992
993 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
994
995 if (dri2_dpy->own_device)
996 wl_display_dispatch_pending(dri2_dpy->wl_dpy);
997
998 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
999 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
1000 dri2_dpy->wl_queue);
1001 wl_registry_add_listener(dri2_dpy->wl_registry,
1002 &registry_listener, dri2_dpy);
1003 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
1004 goto cleanup_dpy;
1005
1006 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
1007 goto cleanup_drm;
1008
1009 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
1010 goto cleanup_fd;
1011
1012 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
1013 if (dri2_dpy->driver_name == NULL) {
1014 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
1015 goto cleanup_fd;
1016 }
1017
1018 if (!dri2_load_driver(disp))
1019 goto cleanup_driver_name;
1020
1021 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1022 dri2_dpy->dri2_loader_extension.base.version = 3;
1023 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
1024 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
1025 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
1026 dri2_get_buffers_with_format;
1027
1028 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
1029 dri2_dpy->extensions[1] = &image_loader_extension.base;
1030 dri2_dpy->extensions[2] = &image_lookup_extension.base;
1031 dri2_dpy->extensions[3] = &use_invalidate.base;
1032 dri2_dpy->extensions[4] = NULL;
1033
1034 dri2_dpy->swap_available = EGL_TRUE;
1035
1036 if (!dri2_create_screen(disp))
1037 goto cleanup_driver;
1038
1039 dri2_setup_swap_interval(dri2_dpy);
1040
1041 /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver
1042 * doesn't have createImageFromFds, since we're using the same driver on
1043 * both sides. We don't want crash if that happens anyway, so fall back to
1044 * gem names if we don't have prime support. */
1045
1046 if (dri2_dpy->image->base.version < 7 ||
1047 dri2_dpy->image->createImageFromFds == NULL)
1048 dri2_dpy->capabilities &= WL_DRM_CAPABILITY_PRIME;
1049
1050 types = EGL_WINDOW_BIT;
1051 for (i = 0; dri2_dpy->driver_configs[i]; i++) {
1052 config = dri2_dpy->driver_configs[i];
1053 if (dri2_dpy->formats & HAS_XRGB8888)
1054 dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks);
1055 if (dri2_dpy->formats & HAS_ARGB8888)
1056 dri2_add_config(disp, config, i + 1, types, NULL, argb_masks);
1057 if (dri2_dpy->formats & HAS_RGB565)
1058 dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks);
1059 }
1060
1061 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1062 disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
1063 disp->Extensions.EXT_buffer_age = EGL_TRUE;
1064 dri2_dpy->authenticate = dri2_wayland_authenticate;
1065
1066 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1067
1068 /* we're supporting EGL 1.4 */
1069 disp->VersionMajor = 1;
1070 disp->VersionMinor = 4;
1071
1072 return EGL_TRUE;
1073
1074 cleanup_driver:
1075 dlclose(dri2_dpy->driver);
1076 cleanup_driver_name:
1077 free(dri2_dpy->driver_name);
1078 cleanup_fd:
1079 close(dri2_dpy->fd);
1080 cleanup_drm:
1081 free(dri2_dpy->device_name);
1082 wl_drm_destroy(dri2_dpy->wl_drm);
1083 cleanup_dpy:
1084 free(dri2_dpy);
1085
1086 return EGL_FALSE;
1087 }