egl/wayland: explicitly set __DRIimageLoaderExtension members
[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 .base = { __DRI_IMAGE_LOADER, 1 },
499
500 .getBuffers = image_get_buffers,
501 .flushFrontBuffer = dri2_flush_front_buffer,
502 };
503
504 static void
505 wayland_throttle_callback(void *data,
506 struct wl_callback *callback,
507 uint32_t time)
508 {
509 struct dri2_egl_surface *dri2_surf = data;
510
511 dri2_surf->throttle_callback = NULL;
512 wl_callback_destroy(callback);
513 }
514
515 static const struct wl_callback_listener throttle_listener = {
516 wayland_throttle_callback
517 };
518
519 static void
520 create_wl_buffer(struct dri2_egl_surface *dri2_surf)
521 {
522 struct dri2_egl_display *dri2_dpy =
523 dri2_egl_display(dri2_surf->base.Resource.Display);
524 int fd, stride, name;
525
526 if (dri2_surf->current->wl_buffer != NULL)
527 return;
528
529 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
530 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
531 __DRI_IMAGE_ATTRIB_FD, &fd);
532 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
533 __DRI_IMAGE_ATTRIB_STRIDE, &stride);
534
535 dri2_surf->current->wl_buffer =
536 wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
537 fd,
538 dri2_surf->base.Width,
539 dri2_surf->base.Height,
540 dri2_surf->format,
541 0, stride,
542 0, 0,
543 0, 0);
544 close(fd);
545 } else {
546 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
547 __DRI_IMAGE_ATTRIB_NAME, &name);
548 dri2_dpy->image->queryImage(dri2_surf->current->dri_image,
549 __DRI_IMAGE_ATTRIB_STRIDE, &stride);
550
551 dri2_surf->current->wl_buffer =
552 wl_drm_create_buffer(dri2_dpy->wl_drm,
553 name,
554 dri2_surf->base.Width,
555 dri2_surf->base.Height,
556 stride,
557 dri2_surf->format);
558 }
559
560 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer,
561 dri2_dpy->wl_queue);
562 wl_buffer_add_listener(dri2_surf->current->wl_buffer,
563 &wl_buffer_listener, dri2_surf);
564 }
565
566 /**
567 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
568 */
569 static EGLBoolean
570 dri2_swap_buffers_with_damage(_EGLDriver *drv,
571 _EGLDisplay *disp,
572 _EGLSurface *draw,
573 const EGLint *rects,
574 EGLint n_rects)
575 {
576 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
577 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
578 struct dri2_egl_context *dri2_ctx;
579 _EGLContext *ctx;
580 int i;
581
582 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
583 if (dri2_surf->color_buffers[i].age > 0)
584 dri2_surf->color_buffers[i].age++;
585
586 /* Make sure we have a back buffer in case we're swapping without ever
587 * rendering. */
588 if (get_back_bo(dri2_surf) < 0) {
589 _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
590 return EGL_FALSE;
591 }
592
593 if (draw->SwapInterval > 0) {
594 dri2_surf->throttle_callback =
595 wl_surface_frame(dri2_surf->wl_win->surface);
596 wl_callback_add_listener(dri2_surf->throttle_callback,
597 &throttle_listener, dri2_surf);
598 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
599 dri2_dpy->wl_queue);
600 }
601
602 dri2_surf->back->age = 1;
603 dri2_surf->current = dri2_surf->back;
604 dri2_surf->back = NULL;
605
606 create_wl_buffer(dri2_surf);
607
608 wl_surface_attach(dri2_surf->wl_win->surface,
609 dri2_surf->current->wl_buffer,
610 dri2_surf->dx, dri2_surf->dy);
611
612 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
613 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
614 /* reset resize growing parameters */
615 dri2_surf->dx = 0;
616 dri2_surf->dy = 0;
617
618 if (n_rects == 0) {
619 wl_surface_damage(dri2_surf->wl_win->surface,
620 0, 0, INT32_MAX, INT32_MAX);
621 } else {
622 for (i = 0; i < n_rects; i++) {
623 const int *rect = &rects[i * 4];
624 wl_surface_damage(dri2_surf->wl_win->surface,
625 rect[0],
626 dri2_surf->base.Height - rect[1] - rect[3],
627 rect[2], rect[3]);
628 }
629 }
630
631 if (dri2_dpy->flush->base.version >= 4) {
632 ctx = _eglGetCurrentContext();
633 dri2_ctx = dri2_egl_context(ctx);
634 (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context,
635 dri2_surf->dri_drawable,
636 __DRI2_FLUSH_DRAWABLE,
637 __DRI2_THROTTLE_SWAPBUFFER);
638 } else {
639 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
640 }
641
642 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
643
644 wl_surface_commit(dri2_surf->wl_win->surface);
645
646 /* If we're not waiting for a frame callback then we'll at least throttle
647 * to a sync callback so that we always give a chance for the compositor to
648 * handle the commit and send a release event before checking for a free
649 * buffer */
650 if (dri2_surf->throttle_callback == NULL) {
651 dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
652 wl_callback_add_listener(dri2_surf->throttle_callback,
653 &throttle_listener, dri2_surf);
654 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
655 dri2_dpy->wl_queue);
656 }
657
658 wl_display_flush(dri2_dpy->wl_dpy);
659
660 return EGL_TRUE;
661 }
662
663 static EGLint
664 dri2_query_buffer_age(_EGLDriver *drv,
665 _EGLDisplay *disp, _EGLSurface *surface)
666 {
667 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
668
669 if (get_back_bo(dri2_surf) < 0) {
670 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
671 return 0;
672 }
673
674 return dri2_surf->back->age;
675 }
676
677 static EGLBoolean
678 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
679 {
680 return dri2_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
681 }
682
683 static struct wl_buffer *
684 dri2_create_wayland_buffer_from_image_wl(_EGLDriver *drv,
685 _EGLDisplay *disp,
686 _EGLImage *img)
687 {
688 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
689 struct dri2_egl_image *dri2_img = dri2_egl_image(img);
690 __DRIimage *image = dri2_img->dri_image;
691 struct wl_buffer *buffer;
692 int width, height, format, pitch;
693 enum wl_drm_format wl_format;
694
695 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
696
697 switch (format) {
698 case __DRI_IMAGE_FORMAT_ARGB8888:
699 if (!(dri2_dpy->formats & HAS_ARGB8888))
700 goto bad_format;
701 wl_format = WL_DRM_FORMAT_ARGB8888;
702 break;
703 case __DRI_IMAGE_FORMAT_XRGB8888:
704 if (!(dri2_dpy->formats & HAS_XRGB8888))
705 goto bad_format;
706 wl_format = WL_DRM_FORMAT_XRGB8888;
707 break;
708 default:
709 goto bad_format;
710 }
711
712 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
713 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
714 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
715
716 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
717 int fd;
718
719 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
720
721 buffer =
722 wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
723 fd,
724 width, height,
725 wl_format,
726 0, pitch,
727 0, 0,
728 0, 0);
729
730 close(fd);
731 } else {
732 int name;
733
734 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
735
736 buffer =
737 wl_drm_create_buffer(dri2_dpy->wl_drm,
738 name,
739 width, height,
740 pitch,
741 wl_format);
742 }
743
744 /* The buffer object will have been created with our internal event queue
745 * because it is using the wl_drm object as a proxy factory. We want the
746 * buffer to be used by the application so we'll reset it to the display's
747 * default event queue */
748 if (buffer)
749 wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
750
751 return buffer;
752
753 bad_format:
754 _eglError(EGL_BAD_MATCH, "unsupported image format");
755 return NULL;
756 }
757
758 static int
759 dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
760 {
761 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
762 int ret = 0;
763
764 dri2_dpy->authenticated = 0;
765
766 wl_drm_authenticate(dri2_dpy->wl_drm, id);
767 if (roundtrip(dri2_dpy) < 0)
768 ret = -1;
769
770 if (!dri2_dpy->authenticated)
771 ret = -1;
772
773 /* reset authenticated */
774 dri2_dpy->authenticated = 1;
775
776 return ret;
777 }
778
779 /**
780 * Called via eglTerminate(), drv->API.Terminate().
781 */
782 static EGLBoolean
783 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
784 {
785 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
786
787 _eglReleaseDisplayResources(drv, disp);
788 _eglCleanupDisplay(disp);
789
790 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
791 close(dri2_dpy->fd);
792 dlclose(dri2_dpy->driver);
793 free(dri2_dpy->driver_name);
794 free(dri2_dpy->device_name);
795 wl_drm_destroy(dri2_dpy->wl_drm);
796 if (dri2_dpy->own_device)
797 wl_display_disconnect(dri2_dpy->wl_dpy);
798 free(dri2_dpy);
799 disp->DriverData = NULL;
800
801 return EGL_TRUE;
802 }
803
804 static void
805 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
806 {
807 struct dri2_egl_display *dri2_dpy = data;
808 drm_magic_t magic;
809
810 dri2_dpy->device_name = strdup(device);
811 if (!dri2_dpy->device_name)
812 return;
813
814 #ifdef O_CLOEXEC
815 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
816 if (dri2_dpy->fd == -1 && errno == EINVAL)
817 #endif
818 {
819 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
820 if (dri2_dpy->fd != -1)
821 fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
822 FD_CLOEXEC);
823 }
824 if (dri2_dpy->fd == -1) {
825 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
826 dri2_dpy->device_name, strerror(errno));
827 return;
828 }
829
830 drmGetMagic(dri2_dpy->fd, &magic);
831 wl_drm_authenticate(dri2_dpy->wl_drm, magic);
832 }
833
834 static void
835 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
836 {
837 struct dri2_egl_display *dri2_dpy = data;
838
839 switch (format) {
840 case WL_DRM_FORMAT_ARGB8888:
841 dri2_dpy->formats |= HAS_ARGB8888;
842 break;
843 case WL_DRM_FORMAT_XRGB8888:
844 dri2_dpy->formats |= HAS_XRGB8888;
845 break;
846 case WL_DRM_FORMAT_RGB565:
847 dri2_dpy->formats |= HAS_RGB565;
848 break;
849 }
850 }
851
852 static void
853 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
854 {
855 struct dri2_egl_display *dri2_dpy = data;
856
857 dri2_dpy->capabilities = value;
858 }
859
860 static void
861 drm_handle_authenticated(void *data, struct wl_drm *drm)
862 {
863 struct dri2_egl_display *dri2_dpy = data;
864
865 dri2_dpy->authenticated = 1;
866 }
867
868 static const struct wl_drm_listener drm_listener = {
869 drm_handle_device,
870 drm_handle_format,
871 drm_handle_authenticated,
872 drm_handle_capabilities
873 };
874
875 static void
876 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
877 const char *interface, uint32_t version)
878 {
879 struct dri2_egl_display *dri2_dpy = data;
880
881 if (version > 1)
882 version = 2;
883 if (strcmp(interface, "wl_drm") == 0) {
884 dri2_dpy->wl_drm =
885 wl_registry_bind(registry, name, &wl_drm_interface, version);
886 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
887 }
888 }
889
890 static void
891 registry_handle_global_remove(void *data, struct wl_registry *registry,
892 uint32_t name)
893 {
894 }
895
896 static const struct wl_registry_listener registry_listener = {
897 registry_handle_global,
898 registry_handle_global_remove
899 };
900
901 static EGLBoolean
902 dri2_swap_interval(_EGLDriver *drv,
903 _EGLDisplay *disp,
904 _EGLSurface *surf,
905 EGLint interval)
906 {
907 if (interval > surf->Config->MaxSwapInterval)
908 interval = surf->Config->MaxSwapInterval;
909 else if (interval < surf->Config->MinSwapInterval)
910 interval = surf->Config->MinSwapInterval;
911
912 surf->SwapInterval = interval;
913
914 return EGL_TRUE;
915 }
916
917 static void
918 dri2_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
919 {
920 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
921
922 /* We can't use values greater than 1 on Wayland because we are using the
923 * frame callback to synchronise the frame and the only way we be sure to
924 * get a frame callback is to attach a new buffer. Therefore we can't just
925 * sit drawing nothing to wait until the next ‘n’ frame callbacks */
926
927 if (dri2_dpy->config)
928 dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
929 "vblank_mode", &vblank_mode);
930 switch (vblank_mode) {
931 case DRI_CONF_VBLANK_NEVER:
932 dri2_dpy->min_swap_interval = 0;
933 dri2_dpy->max_swap_interval = 0;
934 dri2_dpy->default_swap_interval = 0;
935 break;
936 case DRI_CONF_VBLANK_ALWAYS_SYNC:
937 dri2_dpy->min_swap_interval = 1;
938 dri2_dpy->max_swap_interval = 1;
939 dri2_dpy->default_swap_interval = 1;
940 break;
941 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
942 dri2_dpy->min_swap_interval = 0;
943 dri2_dpy->max_swap_interval = 1;
944 dri2_dpy->default_swap_interval = 0;
945 break;
946 default:
947 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
948 dri2_dpy->min_swap_interval = 0;
949 dri2_dpy->max_swap_interval = 1;
950 dri2_dpy->default_swap_interval = 1;
951 break;
952 }
953 }
954
955 EGLBoolean
956 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
957 {
958 struct dri2_egl_display *dri2_dpy;
959 const __DRIconfig *config;
960 uint32_t types;
961 int i;
962 static const unsigned int argb_masks[4] =
963 { 0xff0000, 0xff00, 0xff, 0xff000000 };
964 static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
965 static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 };
966
967 loader_set_logger(_eglLog);
968
969 drv->API.CreateWindowSurface = dri2_create_window_surface;
970 drv->API.DestroySurface = dri2_destroy_surface;
971 drv->API.SwapBuffers = dri2_swap_buffers;
972 drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
973 drv->API.SwapInterval = dri2_swap_interval;
974 drv->API.Terminate = dri2_terminate;
975 drv->API.QueryBufferAge = dri2_query_buffer_age;
976
977 drv->API.CreateWaylandBufferFromImageWL =
978 dri2_create_wayland_buffer_from_image_wl;
979
980 dri2_dpy = calloc(1, sizeof *dri2_dpy);
981 if (!dri2_dpy)
982 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
983
984 disp->DriverData = (void *) dri2_dpy;
985 if (disp->PlatformDisplay == NULL) {
986 dri2_dpy->wl_dpy = wl_display_connect(NULL);
987 if (dri2_dpy->wl_dpy == NULL)
988 goto cleanup_dpy;
989 dri2_dpy->own_device = 1;
990 } else {
991 dri2_dpy->wl_dpy = disp->PlatformDisplay;
992 }
993
994 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
995
996 if (dri2_dpy->own_device)
997 wl_display_dispatch_pending(dri2_dpy->wl_dpy);
998
999 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
1000 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
1001 dri2_dpy->wl_queue);
1002 wl_registry_add_listener(dri2_dpy->wl_registry,
1003 &registry_listener, dri2_dpy);
1004 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
1005 goto cleanup_dpy;
1006
1007 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
1008 goto cleanup_drm;
1009
1010 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
1011 goto cleanup_fd;
1012
1013 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
1014 if (dri2_dpy->driver_name == NULL) {
1015 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
1016 goto cleanup_fd;
1017 }
1018
1019 if (!dri2_load_driver(disp))
1020 goto cleanup_driver_name;
1021
1022 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
1023 dri2_dpy->dri2_loader_extension.base.version = 3;
1024 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
1025 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
1026 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
1027 dri2_get_buffers_with_format;
1028
1029 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
1030 dri2_dpy->extensions[1] = &image_loader_extension.base;
1031 dri2_dpy->extensions[2] = &image_lookup_extension.base;
1032 dri2_dpy->extensions[3] = &use_invalidate.base;
1033 dri2_dpy->extensions[4] = NULL;
1034
1035 dri2_dpy->swap_available = EGL_TRUE;
1036
1037 if (!dri2_create_screen(disp))
1038 goto cleanup_driver;
1039
1040 dri2_setup_swap_interval(dri2_dpy);
1041
1042 /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver
1043 * doesn't have createImageFromFds, since we're using the same driver on
1044 * both sides. We don't want crash if that happens anyway, so fall back to
1045 * gem names if we don't have prime support. */
1046
1047 if (dri2_dpy->image->base.version < 7 ||
1048 dri2_dpy->image->createImageFromFds == NULL)
1049 dri2_dpy->capabilities &= WL_DRM_CAPABILITY_PRIME;
1050
1051 types = EGL_WINDOW_BIT;
1052 for (i = 0; dri2_dpy->driver_configs[i]; i++) {
1053 config = dri2_dpy->driver_configs[i];
1054 if (dri2_dpy->formats & HAS_XRGB8888)
1055 dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks);
1056 if (dri2_dpy->formats & HAS_ARGB8888)
1057 dri2_add_config(disp, config, i + 1, types, NULL, argb_masks);
1058 if (dri2_dpy->formats & HAS_RGB565)
1059 dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks);
1060 }
1061
1062 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1063 disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
1064 disp->Extensions.EXT_buffer_age = EGL_TRUE;
1065 dri2_dpy->authenticate = dri2_wayland_authenticate;
1066
1067 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1068
1069 /* we're supporting EGL 1.4 */
1070 disp->VersionMajor = 1;
1071 disp->VersionMinor = 4;
1072
1073 return EGL_TRUE;
1074
1075 cleanup_driver:
1076 dlclose(dri2_dpy->driver);
1077 cleanup_driver_name:
1078 free(dri2_dpy->driver_name);
1079 cleanup_fd:
1080 close(dri2_dpy->fd);
1081 cleanup_drm:
1082 free(dri2_dpy->device_name);
1083 wl_drm_destroy(dri2_dpy->wl_drm);
1084 cleanup_dpy:
1085 free(dri2_dpy);
1086
1087 return EGL_FALSE;
1088 }