egl_dri2: Drop dri2_surface_type enum
[mesa.git] / src / egl / drivers / dri2 / platform_wayland.c
1 /*
2 * Copyright © 2011 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
40 #include <wayland-client.h>
41 #include "wayland-drm-client-protocol.h"
42
43 static void
44 sync_callback(void *data)
45 {
46 int *done = data;
47
48 *done = 1;
49 }
50
51 static void
52 force_roundtrip(struct wl_display *display)
53 {
54 int done = 0;
55
56 wl_display_sync_callback(display, sync_callback, &done);
57 wl_display_iterate(display, WL_DISPLAY_WRITABLE);
58 while (!done)
59 wl_display_iterate(display, WL_DISPLAY_READABLE);
60 }
61
62 static void
63 wl_buffer_release(void *data, struct wl_buffer *buffer)
64 {
65 struct dri2_egl_surface *dri2_surf = data;
66 int i;
67
68 for (i = 0; i < WL_BUFFER_COUNT; ++i)
69 if (dri2_surf->wl_drm_buffer[i] == buffer)
70 break;
71
72 assert(i <= WL_BUFFER_COUNT);
73
74 /* not found? */
75 if (i == WL_BUFFER_COUNT)
76 return;
77
78 dri2_surf->wl_buffer_lock[i] = 0;
79
80 }
81
82 static struct wl_buffer_listener wl_buffer_listener = {
83 wl_buffer_release
84 };
85
86 /**
87 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
88 */
89 static _EGLSurface *
90 dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
91 _EGLConfig *conf, EGLNativeWindowType window,
92 const EGLint *attrib_list)
93 {
94 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
95 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
96 struct dri2_egl_surface *dri2_surf;
97 struct dri2_egl_buffer *dri2_buf;
98 int i;
99
100 (void) drv;
101
102 dri2_surf = malloc(sizeof *dri2_surf);
103 if (!dri2_surf) {
104 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
105 return NULL;
106 }
107
108 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
109 goto cleanup_surf;
110
111 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
112 dri2_surf->wl_drm_buffer[i] = NULL;
113 dri2_surf->wl_buffer_lock[i] = 0;
114 }
115
116 for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
117 dri2_surf->dri_buffers[i] = NULL;
118
119 dri2_surf->pending_buffer = NULL;
120 dri2_surf->third_buffer = NULL;
121 dri2_surf->block_swap_buffers = EGL_FALSE;
122
123 switch (type) {
124 case EGL_WINDOW_BIT:
125 dri2_surf->wl_win = (struct wl_egl_window *) window;
126
127 dri2_surf->base.Width = -1;
128 dri2_surf->base.Height = -1;
129 break;
130 case EGL_PIXMAP_BIT:
131 dri2_surf->wl_pix = (struct wl_egl_pixmap *) window;
132
133 dri2_surf->base.Width = dri2_surf->wl_pix->width;
134 dri2_surf->base.Height = dri2_surf->wl_pix->height;
135
136 if (dri2_surf->wl_pix->driver_private) {
137 dri2_buf = dri2_surf->wl_pix->driver_private;
138 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = dri2_buf->dri_buffer;
139 }
140 break;
141 default:
142 goto cleanup_surf;
143 }
144
145 dri2_surf->dri_drawable =
146 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
147 type == EGL_WINDOW_BIT ?
148 dri2_conf->dri_double_config :
149 dri2_conf->dri_single_config,
150 dri2_surf);
151 if (dri2_surf->dri_drawable == NULL) {
152 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
153 goto cleanup_dri_drawable;
154 }
155
156 return &dri2_surf->base;
157
158 cleanup_dri_drawable:
159 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
160 cleanup_surf:
161 free(dri2_surf);
162
163 return NULL;
164 }
165
166 /**
167 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
168 */
169 static _EGLSurface *
170 dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
171 _EGLConfig *conf, EGLNativeWindowType window,
172 const EGLint *attrib_list)
173 {
174 return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
175 window, attrib_list);
176 }
177
178 static _EGLSurface *
179 dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
180 _EGLConfig *conf, EGLNativePixmapType pixmap,
181 const EGLint *attrib_list)
182 {
183 return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
184 pixmap, attrib_list);
185 }
186
187 /**
188 * Called via eglDestroySurface(), drv->API.DestroySurface().
189 */
190 static EGLBoolean
191 dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
192 {
193 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
194 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
195 int i;
196
197 (void) drv;
198
199 if (!_eglPutSurface(surf))
200 return EGL_TRUE;
201
202 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
203
204 for (i = 0; i < WL_BUFFER_COUNT; ++i)
205 if (dri2_surf->wl_drm_buffer[i])
206 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
207
208 for (i = 0; i < __DRI_BUFFER_COUNT; ++i)
209 if (dri2_surf->dri_buffers[i] && !(i == __DRI_BUFFER_FRONT_LEFT &&
210 dri2_surf->base.Type == EGL_PIXMAP_BIT))
211 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
212 dri2_surf->dri_buffers[i]);
213
214 if (dri2_surf->third_buffer) {
215 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
216 dri2_surf->third_buffer);
217 }
218
219 free(surf);
220
221 return EGL_TRUE;
222 }
223
224 static void
225 dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
226 {
227 struct dri2_egl_buffer *dri2_buf = egl_pixmap->driver_private;
228
229 assert(dri2_buf);
230
231 dri2_buf->dri2_dpy->dri2->releaseBuffer(dri2_buf->dri2_dpy->dri_screen,
232 dri2_buf->dri_buffer);
233
234 free(dri2_buf);
235
236 egl_pixmap->driver_private = NULL;
237 egl_pixmap->destroy = NULL;
238 }
239
240 static struct wl_buffer *
241 wayland_create_buffer(struct dri2_egl_surface *dri2_surf,
242 __DRIbuffer *buffer,
243 struct wl_visual *visual)
244 {
245 struct dri2_egl_display *dri2_dpy =
246 dri2_egl_display(dri2_surf->base.Resource.Display);
247 struct wl_buffer *buf;
248
249 buf = wl_drm_create_buffer(dri2_dpy->wl_drm, buffer->name,
250 dri2_surf->base.Width, dri2_surf->base.Height,
251 buffer->pitch, visual);
252 wl_buffer_add_listener(buf, &wl_buffer_listener, dri2_surf);
253
254 return buf;
255 }
256
257 static void
258 dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
259 {
260 struct dri2_egl_display *dri2_dpy =
261 dri2_egl_display(dri2_surf->base.Resource.Display);
262
263 (void) format;
264
265 switch (dri2_surf->base.Type) {
266 case EGL_WINDOW_BIT:
267 /* allocate a front buffer for our double-buffered window*/
268 if (dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] != NULL)
269 break;
270 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] =
271 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
272 __DRI_BUFFER_FRONT_LEFT, format,
273 dri2_surf->base.Width, dri2_surf->base.Height);
274 break;
275 default:
276 break;
277 }
278 }
279
280 static void
281 dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
282 {
283 struct dri2_egl_display *dri2_dpy =
284 dri2_egl_display(dri2_surf->base.Resource.Display);
285 struct dri2_egl_buffer *dri2_buf;
286
287 switch (dri2_surf->base.Type) {
288 case EGL_PIXMAP_BIT:
289 dri2_buf = malloc(sizeof *dri2_buf);
290 if (!dri2_buf)
291 return;
292
293 dri2_buf->dri_buffer = dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT];
294 dri2_buf->dri2_dpy = dri2_dpy;
295
296 dri2_surf->wl_pix->driver_private = dri2_buf;
297 dri2_surf->wl_pix->destroy = dri2_wl_egl_pixmap_destroy;
298 break;
299 default:
300 break;
301 }
302 }
303
304 static void
305 dri2_release_pending_buffer(void *data)
306 {
307 struct dri2_egl_surface *dri2_surf = data;
308 struct dri2_egl_display *dri2_dpy =
309 dri2_egl_display(dri2_surf->base.Resource.Display);
310
311 /* FIXME: print internal error */
312 if (!dri2_surf->pending_buffer)
313 return;
314
315 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
316 dri2_surf->pending_buffer);
317 dri2_surf->pending_buffer = NULL;
318 }
319
320 static void
321 dri2_release_buffers(struct dri2_egl_surface *dri2_surf)
322 {
323 struct dri2_egl_display *dri2_dpy =
324 dri2_egl_display(dri2_surf->base.Resource.Display);
325 int i;
326
327 if (dri2_surf->third_buffer) {
328 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
329 dri2_surf->third_buffer);
330 dri2_surf->third_buffer = NULL;
331 }
332
333 for (i = 0; i < __DRI_BUFFER_COUNT; ++i) {
334 if (dri2_surf->dri_buffers[i]) {
335 switch (i) {
336 case __DRI_BUFFER_FRONT_LEFT:
337 if (dri2_surf->pending_buffer)
338 force_roundtrip(dri2_dpy->wl_dpy);
339 dri2_surf->pending_buffer = dri2_surf->dri_buffers[i];
340 wl_display_sync_callback(dri2_dpy->wl_dpy,
341 dri2_release_pending_buffer, dri2_surf);
342 break;
343 default:
344 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
345 dri2_surf->dri_buffers[i]);
346 break;
347 }
348 dri2_surf->dri_buffers[i] = NULL;
349 }
350 }
351 }
352
353 static inline void
354 pointer_swap(const void **p1, const void **p2)
355 {
356 const void *tmp = *p1;
357 *p1 = *p2;
358 *p2 = tmp;
359 }
360
361 static void
362 destroy_third_buffer(struct dri2_egl_surface *dri2_surf)
363 {
364 struct dri2_egl_display *dri2_dpy =
365 dri2_egl_display(dri2_surf->base.Resource.Display);
366
367 if (dri2_surf->third_buffer == NULL)
368 return;
369
370 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
371 dri2_surf->third_buffer);
372 dri2_surf->third_buffer = NULL;
373
374 if (dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD])
375 wl_buffer_destroy(dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD]);
376 dri2_surf->wl_drm_buffer[WL_BUFFER_THIRD] = NULL;
377 dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD] = 0;
378 }
379
380 static void
381 swap_wl_buffers(struct dri2_egl_surface *dri2_surf,
382 enum wayland_buffer_type a, enum wayland_buffer_type b)
383 {
384 int tmp;
385
386 tmp = dri2_surf->wl_buffer_lock[a];
387 dri2_surf->wl_buffer_lock[a] = dri2_surf->wl_buffer_lock[b];
388 dri2_surf->wl_buffer_lock[b] = tmp;
389
390 pointer_swap((const void **) &dri2_surf->wl_drm_buffer[a],
391 (const void **) &dri2_surf->wl_drm_buffer[b]);
392 }
393
394 static void
395 swap_back_and_third(struct dri2_egl_surface *dri2_surf)
396 {
397 if (dri2_surf->wl_buffer_lock[WL_BUFFER_THIRD])
398 destroy_third_buffer(dri2_surf);
399
400 pointer_swap((const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT],
401 (const void **) &dri2_surf->third_buffer);
402
403 swap_wl_buffers(dri2_surf, WL_BUFFER_BACK, WL_BUFFER_THIRD);
404 }
405
406 static void
407 dri2_prior_buffer_creation(struct dri2_egl_surface *dri2_surf,
408 unsigned int type)
409 {
410 switch (type) {
411 case __DRI_BUFFER_BACK_LEFT:
412 if (dri2_surf->wl_buffer_lock[WL_BUFFER_BACK])
413 swap_back_and_third(dri2_surf);
414 else if (dri2_surf->third_buffer)
415 destroy_third_buffer(dri2_surf);
416 break;
417 default:
418 break;
419
420 }
421 }
422
423 static __DRIbuffer *
424 dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
425 int *width, int *height,
426 unsigned int *attachments, int count,
427 int *out_count, void *loaderPrivate)
428 {
429 struct dri2_egl_surface *dri2_surf = loaderPrivate;
430 struct dri2_egl_display *dri2_dpy =
431 dri2_egl_display(dri2_surf->base.Resource.Display);
432 int i;
433
434 if (dri2_surf->base.Type == EGL_WINDOW_BIT &&
435 (dri2_surf->base.Width != dri2_surf->wl_win->width ||
436 dri2_surf->base.Height != dri2_surf->wl_win->height)) {
437
438 dri2_release_buffers(dri2_surf);
439
440 dri2_surf->base.Width = dri2_surf->wl_win->width;
441 dri2_surf->base.Height = dri2_surf->wl_win->height;
442 dri2_surf->dx = dri2_surf->wl_win->dx;
443 dri2_surf->dy = dri2_surf->wl_win->dy;
444
445 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
446 if (dri2_surf->wl_drm_buffer[i])
447 wl_buffer_destroy(dri2_surf->wl_drm_buffer[i]);
448 dri2_surf->wl_drm_buffer[i] = NULL;
449 dri2_surf->wl_buffer_lock[i] = 0;
450 }
451 }
452
453 dri2_surf->buffer_count = 0;
454 for (i = 0; i < 2*count; i+=2) {
455 assert(attachments[i] < __DRI_BUFFER_COUNT);
456 assert(dri2_surf->buffer_count < 5);
457
458 dri2_prior_buffer_creation(dri2_surf, attachments[i]);
459
460 if (dri2_surf->dri_buffers[attachments[i]] == NULL) {
461
462 dri2_surf->dri_buffers[attachments[i]] =
463 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
464 attachments[i], attachments[i+1],
465 dri2_surf->base.Width, dri2_surf->base.Height);
466
467 if (!dri2_surf->dri_buffers[attachments[i]])
468 continue;
469
470 if (attachments[i] == __DRI_BUFFER_FRONT_LEFT)
471 dri2_process_front_buffer(dri2_surf, attachments[i+1]);
472 else if (attachments[i] == __DRI_BUFFER_BACK_LEFT)
473 dri2_process_back_buffer(dri2_surf, attachments[i+1]);
474 }
475
476 memcpy(&dri2_surf->buffers[dri2_surf->buffer_count],
477 dri2_surf->dri_buffers[attachments[i]],
478 sizeof(__DRIbuffer));
479
480 dri2_surf->buffer_count++;
481 }
482
483 assert(dri2_surf->base.Type == EGL_PIXMAP_BIT ||
484 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
485
486 if (dri2_surf->base.Type == EGL_PIXMAP_BIT && !dri2_surf->wl_pix->buffer)
487 dri2_surf->wl_pix->buffer =
488 wayland_create_buffer(dri2_surf,
489 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
490 dri2_surf->wl_pix->visual);
491
492 *out_count = dri2_surf->buffer_count;
493 if (dri2_surf->buffer_count == 0)
494 return NULL;
495
496 *width = dri2_surf->base.Width;
497 *height = dri2_surf->base.Height;
498
499 return dri2_surf->buffers;
500 }
501
502 static __DRIbuffer *
503 dri2_get_buffers(__DRIdrawable * driDrawable,
504 int *width, int *height,
505 unsigned int *attachments, int count,
506 int *out_count, void *loaderPrivate)
507 {
508 unsigned int *attachments_with_format;
509 __DRIbuffer *buffer;
510 const unsigned int format = 32;
511 int i;
512
513 attachments_with_format = calloc(count * 2, sizeof(unsigned int));
514 if (!attachments_with_format) {
515 *out_count = 0;
516 return NULL;
517 }
518
519 for (i = 0; i < count; ++i) {
520 attachments_with_format[2*i] = attachments[i];
521 attachments_with_format[2*i + 1] = format;
522 }
523
524 buffer =
525 dri2_get_buffers_with_format(driDrawable,
526 width, height,
527 attachments_with_format, count,
528 out_count, loaderPrivate);
529
530 free(attachments_with_format);
531
532 return buffer;
533 }
534
535
536 static void
537 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
538 {
539 (void) driDrawable;
540
541 /* FIXME: Does EGL support front buffer rendering at all? */
542
543 #if 0
544 struct dri2_egl_surface *dri2_surf = loaderPrivate;
545
546 dri2WaitGL(dri2_surf);
547 #else
548 (void) loaderPrivate;
549 #endif
550 }
551
552 static void
553 wayland_frame_callback(struct wl_surface *surface, void *data, uint32_t time)
554 {
555 struct dri2_egl_surface *dri2_surf = data;
556
557 dri2_surf->block_swap_buffers = EGL_FALSE;
558 }
559
560 /**
561 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
562 */
563 static EGLBoolean
564 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
565 {
566 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
567 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
568 struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
569
570 while (dri2_surf->block_swap_buffers)
571 wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE);
572
573 dri2_surf->block_swap_buffers = EGL_TRUE;
574 wl_display_frame_callback(dri2_dpy->wl_dpy,
575 dri2_surf->wl_win->surface,
576 wayland_frame_callback, dri2_surf);
577
578 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
579 pointer_swap(
580 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
581 (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
582
583 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment =
584 __DRI_BUFFER_FRONT_LEFT;
585 dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment =
586 __DRI_BUFFER_BACK_LEFT;
587
588 swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK);
589
590 if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT])
591 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] =
592 wayland_create_buffer(dri2_surf,
593 dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
594 dri2_surf->wl_win->visual);
595
596 wl_buffer_damage(dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 0, 0,
597 dri2_surf->base.Width, dri2_surf->base.Height);
598 wl_surface_attach(dri2_surf->wl_win->surface,
599 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
600 dri2_surf->dx, dri2_surf->dy);
601 dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1;
602
603 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
604 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
605 /* reset resize growing parameters */
606 dri2_surf->dx = 0;
607 dri2_surf->dy = 0;
608
609 wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
610 dri2_surf->base.Width, dri2_surf->base.Height);
611 }
612
613 _EGLContext *ctx;
614 if (dri2_drv->glFlush) {
615 ctx = _eglGetCurrentContext();
616 if (ctx && ctx->DrawSurface == &dri2_surf->base)
617 dri2_drv->glFlush();
618 }
619
620 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
621 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
622
623 return EGL_TRUE;
624 }
625
626 /**
627 * Called via eglCreateImageKHR(), drv->API.CreateImageKHR().
628 */
629 static _EGLImage *
630 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
631 EGLClientBuffer buffer, const EGLint *attr_list)
632 {
633 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
634 struct wl_egl_pixmap *wl_egl_pixmap = (struct wl_egl_pixmap *) buffer;
635 struct dri2_egl_buffer *dri2_buf;
636 EGLint wl_attr_list[] = {
637 EGL_WIDTH, 0,
638 EGL_HEIGHT, 0,
639 EGL_DRM_BUFFER_STRIDE_MESA, 0,
640 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
641 EGL_NONE
642 };
643
644 dri2_buf = malloc(sizeof *dri2_buf);
645 if (!dri2_buf)
646 return NULL;
647
648 dri2_buf->dri2_dpy = dri2_dpy;
649 dri2_buf->dri_buffer =
650 dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
651 __DRI_BUFFER_FRONT_LEFT, 32,
652 wl_egl_pixmap->width,
653 wl_egl_pixmap->height);
654
655 wl_egl_pixmap->destroy = dri2_wl_egl_pixmap_destroy;
656 wl_egl_pixmap->driver_private = dri2_buf;
657
658 wl_egl_pixmap->buffer =
659 wl_drm_create_buffer(dri2_dpy->wl_drm,
660 dri2_buf->dri_buffer->name,
661 wl_egl_pixmap->width,
662 wl_egl_pixmap->height,
663 dri2_buf->dri_buffer->pitch,
664 wl_egl_pixmap->visual);
665
666 wl_attr_list[1] = wl_egl_pixmap->width;
667 wl_attr_list[3] = wl_egl_pixmap->height;
668 wl_attr_list[5] = dri2_buf->dri_buffer->pitch / 4;
669
670 return dri2_create_image_khr(disp->Driver, disp, ctx, EGL_DRM_BUFFER_MESA,
671 (EGLClientBuffer)(intptr_t) dri2_buf->dri_buffer->name, wl_attr_list);
672 }
673
674 static _EGLImage *
675 dri2_wayland_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
676 _EGLContext *ctx, EGLenum target,
677 EGLClientBuffer buffer, const EGLint *attr_list)
678 {
679 (void) drv;
680
681 switch (target) {
682 case EGL_NATIVE_PIXMAP_KHR:
683 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
684 default:
685 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
686 }
687 }
688
689 static int
690 dri2_wayland_authenticate(_EGLDisplay *disp, uint32_t id)
691 {
692 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
693 int ret = 0;
694
695 dri2_dpy->authenticated = 0;
696
697 wl_drm_authenticate(dri2_dpy->wl_drm, id);
698 force_roundtrip(dri2_dpy->wl_dpy);
699
700 if (!dri2_dpy->authenticated)
701 ret = -1;
702
703 /* reset authenticated */
704 dri2_dpy->authenticated = 1;
705
706 return ret;
707 }
708
709 /**
710 * Called via eglTerminate(), drv->API.Terminate().
711 */
712 static EGLBoolean
713 dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
714 {
715 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
716
717 _eglReleaseDisplayResources(drv, disp);
718 _eglCleanupDisplay(disp);
719
720 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
721 close(dri2_dpy->fd);
722 dlclose(dri2_dpy->driver);
723 free(dri2_dpy->driver_name);
724 free(dri2_dpy);
725 disp->DriverData = NULL;
726
727 return EGL_TRUE;
728 }
729
730 static void
731 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
732 {
733 struct dri2_egl_display *dri2_dpy = data;
734 drm_magic_t magic;
735
736 dri2_dpy->device_name = strdup(device);
737 if (!dri2_dpy->device_name)
738 return;
739
740 dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
741 if (dri2_dpy->fd == -1) {
742 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
743 dri2_dpy->device_name, strerror(errno));
744 return;
745 }
746
747 drmGetMagic(dri2_dpy->fd, &magic);
748 wl_drm_authenticate(dri2_dpy->wl_drm, magic);
749 }
750
751 static void
752 drm_handle_authenticated(void *data, struct wl_drm *drm)
753 {
754 struct dri2_egl_display *dri2_dpy = data;
755
756 dri2_dpy->authenticated = 1;
757 }
758
759 static const struct wl_drm_listener drm_listener = {
760 drm_handle_device,
761 drm_handle_authenticated
762 };
763
764 EGLBoolean
765 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
766 {
767 struct dri2_egl_display *dri2_dpy;
768 uint32_t id;
769 int i;
770
771 drv->API.CreateWindowSurface = dri2_create_window_surface;
772 drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
773 drv->API.DestroySurface = dri2_destroy_surface;
774 drv->API.SwapBuffers = dri2_swap_buffers;
775 drv->API.CreateImageKHR = dri2_wayland_create_image_khr;
776 drv->API.Terminate = dri2_terminate;
777
778 dri2_dpy = malloc(sizeof *dri2_dpy);
779 if (!dri2_dpy)
780 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
781
782 memset(dri2_dpy, 0, sizeof *dri2_dpy);
783
784 disp->DriverData = (void *) dri2_dpy;
785 if (disp->PlatformDisplay == NULL) {
786 dri2_dpy->wl_dpy = wl_display_connect(NULL);
787 if (dri2_dpy->wl_dpy == NULL)
788 goto cleanup_dpy;
789 } else {
790 dri2_dpy->wl_dpy = disp->PlatformDisplay;
791 }
792
793 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1);
794 if (id == 0)
795 force_roundtrip(dri2_dpy->wl_dpy);
796 id = wl_display_get_global(dri2_dpy->wl_dpy, "wl_drm", 1);
797 if (id == 0)
798 goto cleanup_dpy;
799 dri2_dpy->wl_drm = wl_drm_create(dri2_dpy->wl_dpy, id, 1);
800 if (!dri2_dpy->wl_drm)
801 goto cleanup_dpy;
802 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
803 force_roundtrip(dri2_dpy->wl_dpy);
804 if (dri2_dpy->fd == -1)
805 goto cleanup_drm;
806
807 force_roundtrip(dri2_dpy->wl_dpy);
808 if (!dri2_dpy->authenticated)
809 goto cleanup_fd;
810
811 dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
812 if (dri2_dpy->driver_name == NULL) {
813 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
814 goto cleanup_fd;
815 }
816
817 if (!dri2_load_driver(disp))
818 goto cleanup_driver_name;
819
820 dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
821 dri2_dpy->dri2_loader_extension.base.version = 3;
822 dri2_dpy->dri2_loader_extension.getBuffers = dri2_get_buffers;
823 dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
824 dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
825 dri2_get_buffers_with_format;
826
827 dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
828 dri2_dpy->extensions[1] = &image_lookup_extension.base;
829 dri2_dpy->extensions[2] = &use_invalidate.base;
830 dri2_dpy->extensions[3] = NULL;
831
832 if (!dri2_create_screen(disp))
833 goto cleanup_driver;
834
835 for (i = 0; dri2_dpy->driver_configs[i]; i++)
836 dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0,
837 EGL_WINDOW_BIT | EGL_PIXMAP_BIT, NULL, NULL);
838
839
840 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
841
842 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
843 dri2_dpy->authenticate = dri2_wayland_authenticate;
844
845 /* we're supporting EGL 1.4 */
846 disp->VersionMajor = 1;
847 disp->VersionMinor = 4;
848
849 return EGL_TRUE;
850
851 cleanup_driver:
852 dlclose(dri2_dpy->driver);
853 cleanup_driver_name:
854 free(dri2_dpy->driver_name);
855 cleanup_fd:
856 close(dri2_dpy->fd);
857 cleanup_drm:
858 free(dri2_dpy->device_name);
859 wl_drm_destroy(dri2_dpy->wl_drm);
860 cleanup_dpy:
861 free(dri2_dpy);
862
863 return EGL_FALSE;
864 }