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