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