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