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