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