1 /*
2 * Copyright © 2011-2012 Intel Corporation
3 * Copyright © 2012 Collabora, Ltd.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Kristian Høgsberg <krh@bitplanet.net>
27 * Benjamin Franzke <benjaminfranzke@googlemail.com>
28 */
29
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <dlfcn.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <xf86drm.h>
39 #include <sys/mman.h>
40
41 #include "egl_dri2.h"
42 #include "egl_dri2_fallbacks.h"
43 #include "loader.h"
44
45 #include <wayland-client.h>
46 #include "wayland-drm-client-protocol.h"
47
48 enum wl_drm_format_flags {
49 HAS_ARGB8888 = 1,
50 HAS_XRGB8888 = 2,
51 HAS_RGB565 = 4,
52 };
53
54 static EGLBoolean
55 dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
56 EGLint interval);
57
58 static void
sync_callback(void * data,struct wl_callback * callback,uint32_t serial)59 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
60 {
61 int *done = data;
62
63 *done = 1;
64 wl_callback_destroy(callback);
65 }
66
67 static const struct wl_callback_listener sync_listener = {
68 .done = sync_callback
69 };
70
71 static int
roundtrip(struct dri2_egl_display * dri2_dpy)72 roundtrip(struct dri2_egl_display *dri2_dpy)
73 {
74 struct wl_callback *callback;
75 int done = 0, ret = 0;
76
77 callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
78 wl_callback_add_listener(callback, &sync_listener, &done);
79 while (ret != -1 && !done)
80 ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
81
82 if (!done)
83 wl_callback_destroy(callback);
84
85 return ret;
86 }
87
88 static void
wl_buffer_release(void * data,struct wl_buffer * buffer)89 wl_buffer_release(void *data, struct wl_buffer *buffer)
90 {
91 struct dri2_egl_surface *dri2_surf = data;
92 int i;
93
94 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
95 if (dri2_surf->color_buffers[i].wl_buffer == buffer)
96 break;
97
98 if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
99 wl_buffer_destroy(buffer);
100 return;
101 }
102
103 dri2_surf->color_buffers[i].locked = 0;
104 }
105
106 static const struct wl_buffer_listener wl_buffer_listener = {
107 .release = wl_buffer_release
108 };
109
110 static void
resize_callback(struct wl_egl_window * wl_win,void * data)111 resize_callback(struct wl_egl_window *wl_win, void *data)
112 {
113 struct dri2_egl_surface *dri2_surf = data;
114 struct dri2_egl_display *dri2_dpy =
115 dri2_egl_display(dri2_surf->base.Resource.Display);
116
117 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
118 }
119
120 static void
destroy_window_callback(void * data)121 destroy_window_callback(void *data)
122 {
123 struct dri2_egl_surface *dri2_surf = data;
124 dri2_surf->wl_win = NULL;
125 }
126
127 /**
128 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
129 */
130 static _EGLSurface *
dri2_wl_create_window_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)131 dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
132 _EGLConfig *conf, void *native_window,
133 const EGLint *attrib_list)
134 {
135 __DRIcreateNewDrawableFunc createNewDrawable;
136 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
137 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
138 struct wl_egl_window *window = native_window;
139 struct dri2_egl_surface *dri2_surf;
140 const __DRIconfig *config;
141
142 dri2_surf = calloc(1, sizeof *dri2_surf);
143 if (!dri2_surf) {
144 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
145 return NULL;
146 }
147
148 if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list))
149 goto cleanup_surf;
150
151 if (dri2_dpy->dri2) {
152 if (conf->RedSize == 5)
153 dri2_surf->format = WL_DRM_FORMAT_RGB565;
154 else if (conf->AlphaSize == 0)
155 dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
156 else
157 dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
158 } else {
159 if (conf->RedSize == 5)
160 dri2_surf->format = WL_SHM_FORMAT_RGB565;
161 else if (conf->AlphaSize == 0)
162 dri2_surf->format = WL_SHM_FORMAT_XRGB8888;
163 else
164 dri2_surf->format = WL_SHM_FORMAT_ARGB8888;
165 }
166
167 if (!window) {
168 _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
169 goto cleanup_surf;
170 }
171
172 dri2_surf->wl_win = window;
173
174 dri2_surf->wl_win->private = dri2_surf;
175 dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
176
177 dri2_surf->base.Width = -1;
178 dri2_surf->base.Height = -1;
179
180 config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
181 dri2_surf->base.GLColorspace);
182
183 if (dri2_dpy->dri2) {
184 dri2_surf->wl_win->resize_callback = resize_callback;
185
186 createNewDrawable = dri2_dpy->dri2->createNewDrawable;
187 } else {
188 createNewDrawable = dri2_dpy->swrast->createNewDrawable;
189 }
190
191 dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config,
192 dri2_surf);
193 if (dri2_surf->dri_drawable == NULL) {
194 _eglError(EGL_BAD_ALLOC, "createNewDrawable");
195 goto cleanup_surf;
196 }
197
198 dri2_wl_swap_interval(drv, disp, &dri2_surf->base,
199 dri2_dpy->default_swap_interval);
200
201 return &dri2_surf->base;
202
203 cleanup_surf:
204 free(dri2_surf);
205
206 return NULL;
207 }
208
209 static _EGLSurface *
dri2_wl_create_pixmap_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)210 dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
211 _EGLConfig *conf, void *native_window,
212 const EGLint *attrib_list)
213 {
214 /* From the EGL_EXT_platform_wayland spec, version 3:
215 *
216 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
217 * that belongs to Wayland. Any such call fails and generates
218 * EGL_BAD_PARAMETER.
219 */
220 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
221 "Wayland");
222 return NULL;
223 }
224
225 /**
226 * Called via eglDestroySurface(), drv->API.DestroySurface().
227 */
228 static EGLBoolean
dri2_wl_destroy_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf)229 dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
230 {
231 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
232 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
233 int i;
234
235 (void) drv;
236
237 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
238
239 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
240 if (dri2_surf->color_buffers[i].wl_buffer)
241 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
242 if (dri2_surf->color_buffers[i].dri_image)
243 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
244 if (dri2_surf->color_buffers[i].linear_copy)
245 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
246 if (dri2_surf->color_buffers[i].data)
247 munmap(dri2_surf->color_buffers[i].data,
248 dri2_surf->color_buffers[i].data_size);
249 }
250
251 if (dri2_dpy->dri2) {
252 for (i = 0; i < __DRI_BUFFER_COUNT; i++)
253 if (dri2_surf->dri_buffers[i] &&
254 dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
255 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
256 dri2_surf->dri_buffers[i]);
257 }
258
259 if (dri2_surf->throttle_callback)
260 wl_callback_destroy(dri2_surf->throttle_callback);
261
262 if (dri2_surf->wl_win) {
263 dri2_surf->wl_win->private = NULL;
264 dri2_surf->wl_win->resize_callback = NULL;
265 dri2_surf->wl_win->destroy_window_callback = NULL;
266 }
267
268 free(surf);
269
270 return EGL_TRUE;
271 }
272
273 static void
dri2_wl_release_buffers(struct dri2_egl_surface * dri2_surf)274 dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
275 {
276 struct dri2_egl_display *dri2_dpy =
277 dri2_egl_display(dri2_surf->base.Resource.Display);
278 int i;
279
280 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
281 if (dri2_surf->color_buffers[i].wl_buffer &&
282 !dri2_surf->color_buffers[i].locked)
283 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
284 if (dri2_surf->color_buffers[i].dri_image)
285 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
286 if (dri2_surf->color_buffers[i].linear_copy)
287 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
288 if (dri2_surf->color_buffers[i].data)
289 munmap(dri2_surf->color_buffers[i].data,
290 dri2_surf->color_buffers[i].data_size);
291
292 dri2_surf->color_buffers[i].wl_buffer = NULL;
293 dri2_surf->color_buffers[i].dri_image = NULL;
294 dri2_surf->color_buffers[i].linear_copy = NULL;
295 dri2_surf->color_buffers[i].data = NULL;
296 dri2_surf->color_buffers[i].locked = 0;
297 }
298
299 if (dri2_dpy->dri2) {
300 for (i = 0; i < __DRI_BUFFER_COUNT; i++)
301 if (dri2_surf->dri_buffers[i] &&
302 dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
303 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
304 dri2_surf->dri_buffers[i]);
305 }
306 }
307
308 static int
get_back_bo(struct dri2_egl_surface * dri2_surf)309 get_back_bo(struct dri2_egl_surface *dri2_surf)
310 {
311 struct dri2_egl_display *dri2_dpy =
312 dri2_egl_display(dri2_surf->base.Resource.Display);
313 int i, use_flags;
314 unsigned int dri_image_format;
315
316 /* currently supports three WL DRM formats,
317 * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
318 * and WL_DRM_FORMAT_RGB565
319 */
320 switch (dri2_surf->format) {
321 case WL_DRM_FORMAT_ARGB8888:
322 dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
323 break;
324 case WL_DRM_FORMAT_XRGB8888:
325 dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
326 break;
327 case WL_DRM_FORMAT_RGB565:
328 dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
329 break;
330 default:
331 /* format is not supported */
332 return -1;
333 }
334
335 /* There might be a buffer release already queued that wasn't processed */
336 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
337
338 if (dri2_surf->back == NULL) {
339 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
340 /* Get an unlocked buffer, preferrably one with a dri_buffer
341 * already allocated. */
342 if (dri2_surf->color_buffers[i].locked)
343 continue;
344 if (dri2_surf->back == NULL)
345 dri2_surf->back = &dri2_surf->color_buffers[i];
346 else if (dri2_surf->back->dri_image == NULL)
347 dri2_surf->back = &dri2_surf->color_buffers[i];
348 }
349 }
350
351 if (dri2_surf->back == NULL)
352 return -1;
353
354 use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
355
356 if (dri2_dpy->is_different_gpu &&
357 dri2_surf->back->linear_copy == NULL) {
358 dri2_surf->back->linear_copy =
359 dri2_dpy->image->createImage(dri2_dpy->dri_screen,
360 dri2_surf->base.Width,
361 dri2_surf->base.Height,
362 dri_image_format,
363 use_flags |
364 __DRI_IMAGE_USE_LINEAR,
365 NULL);
366 if (dri2_surf->back->linear_copy == NULL)
367 return -1;
368 }
369
370 if (dri2_surf->back->dri_image == NULL) {
371 dri2_surf->back->dri_image =
372 dri2_dpy->image->createImage(dri2_dpy->dri_screen,
373 dri2_surf->base.Width,
374 dri2_surf->base.Height,
375 dri_image_format,
376 dri2_dpy->is_different_gpu ?
377 0 : use_flags,
378 NULL);
379 dri2_surf->back->age = 0;
380 }
381 if (dri2_surf->back->dri_image == NULL)
382 return -1;
383
384 dri2_surf->back->locked = 1;
385
386 return 0;
387 }
388
389
390 static void
back_bo_to_dri_buffer(struct dri2_egl_surface * dri2_surf,__DRIbuffer * buffer)391 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
392 {
393 struct dri2_egl_display *dri2_dpy =
394 dri2_egl_display(dri2_surf->base.Resource.Display);
395 __DRIimage *image;
396 int name, pitch;
397
398 image = dri2_surf->back->dri_image;
399
400 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
401 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
402
403 buffer->attachment = __DRI_BUFFER_BACK_LEFT;
404 buffer->name = name;
405 buffer->pitch = pitch;
406 buffer->cpp = 4;
407 buffer->flags = 0;
408 }
409
410 static int
get_aux_bo(struct dri2_egl_surface * dri2_surf,unsigned int attachment,unsigned int format,__DRIbuffer * buffer)411 get_aux_bo(struct dri2_egl_surface *dri2_surf,
412 unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
413 {
414 struct dri2_egl_display *dri2_dpy =
415 dri2_egl_display(dri2_surf->base.Resource.Display);
416 __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
417
418 if (b == NULL) {
419 b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
420 attachment, format,
421 dri2_surf->base.Width,
422 dri2_surf->base.Height);
423 dri2_surf->dri_buffers[attachment] = b;
424 }
425 if (b == NULL)
426 return -1;
427
428 memcpy(buffer, b, sizeof *buffer);
429
430 return 0;
431 }
432
433 static int
update_buffers(struct dri2_egl_surface * dri2_surf)434 update_buffers(struct dri2_egl_surface *dri2_surf)
435 {
436 struct dri2_egl_display *dri2_dpy =
437 dri2_egl_display(dri2_surf->base.Resource.Display);
438 int i;
439
440 if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
441 dri2_surf->base.Height != dri2_surf->wl_win->height) {
442
443 dri2_wl_release_buffers(dri2_surf);
444
445 dri2_surf->base.Width = dri2_surf->wl_win->width;
446 dri2_surf->base.Height = dri2_surf->wl_win->height;
447 dri2_surf->dx = dri2_surf->wl_win->dx;
448 dri2_surf->dy = dri2_surf->wl_win->dy;
449 }
450
451 if (get_back_bo(dri2_surf) < 0) {
452 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
453 return -1;
454 }
455
456 /* If we have an extra unlocked buffer at this point, we had to do triple
457 * buffering for a while, but now can go back to just double buffering.
458 * That means we can free any unlocked buffer now. */
459 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
460 if (!dri2_surf->color_buffers[i].locked &&
461 dri2_surf->color_buffers[i].wl_buffer) {
462 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
463 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
464 if (dri2_dpy->is_different_gpu)
465 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
466 dri2_surf->color_buffers[i].wl_buffer = NULL;
467 dri2_surf->color_buffers[i].dri_image = NULL;
468 dri2_surf->color_buffers[i].linear_copy = NULL;
469 }
470 }
471
472 return 0;
473 }
474
475 static __DRIbuffer *
dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)476 dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
477 int *width, int *height,
478 unsigned int *attachments, int count,
479 int *out_count, void *loaderPrivate)
480 {
481 struct dri2_egl_surface *dri2_surf = loaderPrivate;
482 int i, j;
483
484 if (update_buffers(dri2_surf) < 0)
485 return NULL;
486
487 for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
488 switch (attachments[i]) {
489 case __DRI_BUFFER_BACK_LEFT:
490 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
491 break;
492 default:
493 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
494 &dri2_surf->buffers[j]) < 0) {
495 _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
496 return NULL;
497 }
498 break;
499 }
500 }
501
502 *out_count = j;
503 if (j == 0)
504 return NULL;
505
506 *width = dri2_surf->base.Width;
507 *height = dri2_surf->base.Height;
508
509 return dri2_surf->buffers;
510 }
511
512 static __DRIbuffer *
dri2_wl_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)513 dri2_wl_get_buffers(__DRIdrawable * driDrawable,
514 int *width, int *height,
515 unsigned int *attachments, int count,
516 int *out_count, void *loaderPrivate)
517 {
518 struct dri2_egl_surface *dri2_surf = loaderPrivate;
519 unsigned int *attachments_with_format;
520 __DRIbuffer *buffer;
521 unsigned int bpp;
522
523 int i;
524
525 switch (dri2_surf->format) {
526 case WL_DRM_FORMAT_ARGB8888:
527 case WL_DRM_FORMAT_XRGB8888:
528 bpp = 32;
529 break;
530 case WL_DRM_FORMAT_RGB565:
531 bpp = 16;
532 break;
533 default:
534 /* format is not supported */
535 return NULL;
536 }
537
538 attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
539 if (!attachments_with_format) {
540 *out_count = 0;
541 return NULL;
542 }
543
544 for (i = 0; i < count; ++i) {
545 attachments_with_format[2*i] = attachments[i];
546 attachments_with_format[2*i + 1] = bpp;
547 }
548
549 buffer =
550 dri2_wl_get_buffers_with_format(driDrawable,
551 width, height,
552 attachments_with_format, count,
553 out_count, loaderPrivate);
554
555 free(attachments_with_format);
556
557 return buffer;
558 }
559
560 static int
image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)561 image_get_buffers(__DRIdrawable *driDrawable,
562 unsigned int format,
563 uint32_t *stamp,
564 void *loaderPrivate,
565 uint32_t buffer_mask,
566 struct __DRIimageList *buffers)
567 {
568 struct dri2_egl_surface *dri2_surf = loaderPrivate;
569
570 if (update_buffers(dri2_surf) < 0)
571 return 0;
572
573 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
574 buffers->back = dri2_surf->back->dri_image;
575
576 return 1;
577 }
578
579 static void
dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)580 dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
581 {
582 (void) driDrawable;
583 (void) loaderPrivate;
584 }
585
586 static const __DRIdri2LoaderExtension dri2_loader_extension = {
587 .base = { __DRI_DRI2_LOADER, 3 },
588
589 .getBuffers = dri2_wl_get_buffers,
590 .flushFrontBuffer = dri2_wl_flush_front_buffer,
591 .getBuffersWithFormat = dri2_wl_get_buffers_with_format,
592 };
593
594 static const __DRIimageLoaderExtension image_loader_extension = {
595 .base = { __DRI_IMAGE_LOADER, 1 },
596
597 .getBuffers = image_get_buffers,
598 .flushFrontBuffer = dri2_wl_flush_front_buffer,
599 };
600
601 static void
wayland_throttle_callback(void * data,struct wl_callback * callback,uint32_t time)602 wayland_throttle_callback(void *data,
603 struct wl_callback *callback,
604 uint32_t time)
605 {
606 struct dri2_egl_surface *dri2_surf = data;
607
608 dri2_surf->throttle_callback = NULL;
609 wl_callback_destroy(callback);
610 }
611
612 static const struct wl_callback_listener throttle_listener = {
613 .done = wayland_throttle_callback
614 };
615
616 static void
create_wl_buffer(struct dri2_egl_surface * dri2_surf)617 create_wl_buffer(struct dri2_egl_surface *dri2_surf)
618 {
619 struct dri2_egl_display *dri2_dpy =
620 dri2_egl_display(dri2_surf->base.Resource.Display);
621 __DRIimage *image;
622 int fd, stride, name;
623
624 if (dri2_surf->current->wl_buffer != NULL)
625 return;
626
627 if (dri2_dpy->is_different_gpu) {
628 image = dri2_surf->current->linear_copy;
629 } else {
630 image = dri2_surf->current->dri_image;
631 }
632 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
633 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
634 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
635
636 dri2_surf->current->wl_buffer =
637 wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
638 fd,
639 dri2_surf->base.Width,
640 dri2_surf->base.Height,
641 dri2_surf->format,
642 0, stride,
643 0, 0,
644 0, 0);
645 close(fd);
646 } else {
647 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
648 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
649
650 dri2_surf->current->wl_buffer =
651 wl_drm_create_buffer(dri2_dpy->wl_drm,
652 name,
653 dri2_surf->base.Width,
654 dri2_surf->base.Height,
655 stride,
656 dri2_surf->format);
657 }
658
659 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer,
660 dri2_dpy->wl_queue);
661 wl_buffer_add_listener(dri2_surf->current->wl_buffer,
662 &wl_buffer_listener, dri2_surf);
663 }
664
665 static EGLBoolean
try_damage_buffer(struct dri2_egl_surface * dri2_surf,const EGLint * rects,EGLint n_rects)666 try_damage_buffer(struct dri2_egl_surface *dri2_surf,
667 const EGLint *rects,
668 EGLint n_rects)
669 {
670 int i;
671
672 if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_win->surface)
673 < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
674 return EGL_FALSE;
675
676 for (i = 0; i < n_rects; i++) {
677 const int *rect = &rects[i * 4];
678
679 wl_surface_damage_buffer(dri2_surf->wl_win->surface,
680 rect[0],
681 dri2_surf->base.Height - rect[1] - rect[3],
682 rect[2], rect[3]);
683 }
684 return EGL_TRUE;
685 }
686 /**
687 * Called via eglSwapBuffers(), drv->API.SwapBuffers().
688 */
689 static EGLBoolean
dri2_wl_swap_buffers_with_damage(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)690 dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
691 _EGLDisplay *disp,
692 _EGLSurface *draw,
693 const EGLint *rects,
694 EGLint n_rects)
695 {
696 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
697 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
698 int i;
699
700 while (dri2_surf->throttle_callback != NULL)
701 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
702 dri2_dpy->wl_queue) == -1)
703 return -1;
704
705 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
706 if (dri2_surf->color_buffers[i].age > 0)
707 dri2_surf->color_buffers[i].age++;
708
709 /* Make sure we have a back buffer in case we're swapping without ever
710 * rendering. */
711 if (get_back_bo(dri2_surf) < 0) {
712 _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
713 return EGL_FALSE;
714 }
715
716 if (draw->SwapInterval > 0) {
717 dri2_surf->throttle_callback =
718 wl_surface_frame(dri2_surf->wl_win->surface);
719 wl_callback_add_listener(dri2_surf->throttle_callback,
720 &throttle_listener, dri2_surf);
721 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
722 dri2_dpy->wl_queue);
723 }
724
725 dri2_surf->back->age = 1;
726 dri2_surf->current = dri2_surf->back;
727 dri2_surf->back = NULL;
728
729 create_wl_buffer(dri2_surf);
730
731 wl_surface_attach(dri2_surf->wl_win->surface,
732 dri2_surf->current->wl_buffer,
733 dri2_surf->dx, dri2_surf->dy);
734
735 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
736 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
737 /* reset resize growing parameters */
738 dri2_surf->dx = 0;
739 dri2_surf->dy = 0;
740
741 /* If the compositor doesn't support damage_buffer, we deliberately
742 * ignore the damage region and post maximum damage, due to
743 * https://bugs.freedesktop.org/78190 */
744 if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
745 wl_surface_damage(dri2_surf->wl_win->surface,
746 0, 0, INT32_MAX, INT32_MAX);
747
748 if (dri2_dpy->is_different_gpu) {
749 _EGLContext *ctx = _eglGetCurrentContext();
750 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
751 dri2_dpy->image->blitImage(dri2_ctx->dri_context,
752 dri2_surf->current->linear_copy,
753 dri2_surf->current->dri_image,
754 0, 0, dri2_surf->base.Width,
755 dri2_surf->base.Height,
756 0, 0, dri2_surf->base.Width,
757 dri2_surf->base.Height, 0);
758 }
759
760 dri2_flush_drawable_for_swapbuffers(disp, draw);
761 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
762
763 wl_surface_commit(dri2_surf->wl_win->surface);
764
765 /* If we're not waiting for a frame callback then we'll at least throttle
766 * to a sync callback so that we always give a chance for the compositor to
767 * handle the commit and send a release event before checking for a free
768 * buffer */
769 if (dri2_surf->throttle_callback == NULL) {
770 dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
771 wl_callback_add_listener(dri2_surf->throttle_callback,
772 &throttle_listener, dri2_surf);
773 }
774
775 wl_display_flush(dri2_dpy->wl_dpy);
776
777 return EGL_TRUE;
778 }
779
780 static EGLint
dri2_wl_query_buffer_age(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surface)781 dri2_wl_query_buffer_age(_EGLDriver *drv,
782 _EGLDisplay *disp, _EGLSurface *surface)
783 {
784 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
785
786 if (get_back_bo(dri2_surf) < 0) {
787 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
788 return 0;
789 }
790
791 return dri2_surf->back->age;
792 }
793
794 static EGLBoolean
dri2_wl_swap_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw)795 dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
796 {
797 return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
798 }
799
800 static struct wl_buffer *
dri2_wl_create_wayland_buffer_from_image(_EGLDriver * drv,_EGLDisplay * disp,_EGLImage * img)801 dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
802 _EGLDisplay *disp,
803 _EGLImage *img)
804 {
805 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
806 struct dri2_egl_image *dri2_img = dri2_egl_image(img);
807 __DRIimage *image = dri2_img->dri_image;
808 struct wl_buffer *buffer;
809 int width, height, format, pitch;
810 enum wl_drm_format wl_format;
811
812 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
813
814 switch (format) {
815 case __DRI_IMAGE_FORMAT_ARGB8888:
816 if (!(dri2_dpy->formats & HAS_ARGB8888))
817 goto bad_format;
818 wl_format = WL_DRM_FORMAT_ARGB8888;
819 break;
820 case __DRI_IMAGE_FORMAT_XRGB8888:
821 if (!(dri2_dpy->formats & HAS_XRGB8888))
822 goto bad_format;
823 wl_format = WL_DRM_FORMAT_XRGB8888;
824 break;
825 default:
826 goto bad_format;
827 }
828
829 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
830 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
831 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
832
833 if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
834 int fd;
835
836 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
837
838 buffer =
839 wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
840 fd,
841 width, height,
842 wl_format,
843 0, pitch,
844 0, 0,
845 0, 0);
846
847 close(fd);
848 } else {
849 int name;
850
851 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
852
853 buffer =
854 wl_drm_create_buffer(dri2_dpy->wl_drm,
855 name,
856 width, height,
857 pitch,
858 wl_format);
859 }
860
861 /* The buffer object will have been created with our internal event queue
862 * because it is using the wl_drm object as a proxy factory. We want the
863 * buffer to be used by the application so we'll reset it to the display's
864 * default event queue */
865 if (buffer)
866 wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
867
868 return buffer;
869
870 bad_format:
871 _eglError(EGL_BAD_MATCH, "unsupported image format");
872 return NULL;
873 }
874
875 static int
dri2_wl_authenticate(_EGLDisplay * disp,uint32_t id)876 dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
877 {
878 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
879 int ret = 0;
880
881 if (dri2_dpy->is_render_node) {
882 _eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
883 "authenticate for render-nodes");
884 return 0;
885 }
886 dri2_dpy->authenticated = 0;
887
888 wl_drm_authenticate(dri2_dpy->wl_drm, id);
889 if (roundtrip(dri2_dpy) < 0)
890 ret = -1;
891
892 if (!dri2_dpy->authenticated)
893 ret = -1;
894
895 /* reset authenticated */
896 dri2_dpy->authenticated = 1;
897
898 return ret;
899 }
900
901 static void
drm_handle_device(void * data,struct wl_drm * drm,const char * device)902 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
903 {
904 struct dri2_egl_display *dri2_dpy = data;
905 drm_magic_t magic;
906
907 dri2_dpy->device_name = strdup(device);
908 if (!dri2_dpy->device_name)
909 return;
910
911 dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
912 if (dri2_dpy->fd == -1) {
913 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
914 dri2_dpy->device_name, strerror(errno));
915 return;
916 }
917
918 if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
919 dri2_dpy->authenticated = 1;
920 } else {
921 drmGetMagic(dri2_dpy->fd, &magic);
922 wl_drm_authenticate(dri2_dpy->wl_drm, magic);
923 }
924 }
925
926 static void
drm_handle_format(void * data,struct wl_drm * drm,uint32_t format)927 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
928 {
929 struct dri2_egl_display *dri2_dpy = data;
930
931 switch (format) {
932 case WL_DRM_FORMAT_ARGB8888:
933 dri2_dpy->formats |= HAS_ARGB8888;
934 break;
935 case WL_DRM_FORMAT_XRGB8888:
936 dri2_dpy->formats |= HAS_XRGB8888;
937 break;
938 case WL_DRM_FORMAT_RGB565:
939 dri2_dpy->formats |= HAS_RGB565;
940 break;
941 }
942 }
943
944 static void
drm_handle_capabilities(void * data,struct wl_drm * drm,uint32_t value)945 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
946 {
947 struct dri2_egl_display *dri2_dpy = data;
948
949 dri2_dpy->capabilities = value;
950 }
951
952 static void
drm_handle_authenticated(void * data,struct wl_drm * drm)953 drm_handle_authenticated(void *data, struct wl_drm *drm)
954 {
955 struct dri2_egl_display *dri2_dpy = data;
956
957 dri2_dpy->authenticated = 1;
958 }
959
960 static const struct wl_drm_listener drm_listener = {
961 .device = drm_handle_device,
962 .format = drm_handle_format,
963 .authenticated = drm_handle_authenticated,
964 .capabilities = drm_handle_capabilities
965 };
966
967 static void
registry_handle_global_drm(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)968 registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name,
969 const char *interface, uint32_t version)
970 {
971 struct dri2_egl_display *dri2_dpy = data;
972
973 if (version > 1)
974 version = 2;
975 if (strcmp(interface, "wl_drm") == 0) {
976 dri2_dpy->wl_drm =
977 wl_registry_bind(registry, name, &wl_drm_interface, version);
978 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
979 }
980 }
981
982 static void
registry_handle_global_remove(void * data,struct wl_registry * registry,uint32_t name)983 registry_handle_global_remove(void *data, struct wl_registry *registry,
984 uint32_t name)
985 {
986 }
987
988 static const struct wl_registry_listener registry_listener_drm = {
989 .global = registry_handle_global_drm,
990 .global_remove = registry_handle_global_remove
991 };
992
993 static EGLBoolean
dri2_wl_swap_interval(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)994 dri2_wl_swap_interval(_EGLDriver *drv,
995 _EGLDisplay *disp,
996 _EGLSurface *surf,
997 EGLint interval)
998 {
999 if (interval > surf->Config->MaxSwapInterval)
1000 interval = surf->Config->MaxSwapInterval;
1001 else if (interval < surf->Config->MinSwapInterval)
1002 interval = surf->Config->MinSwapInterval;
1003
1004 surf->SwapInterval = interval;
1005
1006 return EGL_TRUE;
1007 }
1008
1009 static void
dri2_wl_setup_swap_interval(struct dri2_egl_display * dri2_dpy)1010 dri2_wl_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
1011 {
1012 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1013
1014 /* We can't use values greater than 1 on Wayland because we are using the
1015 * frame callback to synchronise the frame and the only way we be sure to
1016 * get a frame callback is to attach a new buffer. Therefore we can't just
1017 * sit drawing nothing to wait until the next ‘n’ frame callbacks */
1018
1019 if (dri2_dpy->config)
1020 dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
1021 "vblank_mode", &vblank_mode);
1022 switch (vblank_mode) {
1023 case DRI_CONF_VBLANK_NEVER:
1024 dri2_dpy->min_swap_interval = 0;
1025 dri2_dpy->max_swap_interval = 0;
1026 dri2_dpy->default_swap_interval = 0;
1027 break;
1028 case DRI_CONF_VBLANK_ALWAYS_SYNC:
1029 dri2_dpy->min_swap_interval = 1;
1030 dri2_dpy->max_swap_interval = 1;
1031 dri2_dpy->default_swap_interval = 1;
1032 break;
1033 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
1034 dri2_dpy->min_swap_interval = 0;
1035 dri2_dpy->max_swap_interval = 1;
1036 dri2_dpy->default_swap_interval = 0;
1037 break;
1038 default:
1039 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
1040 dri2_dpy->min_swap_interval = 0;
1041 dri2_dpy->max_swap_interval = 1;
1042 dri2_dpy->default_swap_interval = 1;
1043 break;
1044 }
1045 }
1046
1047 static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
1048 .authenticate = dri2_wl_authenticate,
1049 .create_window_surface = dri2_wl_create_window_surface,
1050 .create_pixmap_surface = dri2_wl_create_pixmap_surface,
1051 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
1052 .destroy_surface = dri2_wl_destroy_surface,
1053 .create_image = dri2_create_image_khr,
1054 .swap_interval = dri2_wl_swap_interval,
1055 .swap_buffers = dri2_wl_swap_buffers,
1056 .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
1057 .swap_buffers_region = dri2_fallback_swap_buffers_region,
1058 .post_sub_buffer = dri2_fallback_post_sub_buffer,
1059 .copy_buffers = dri2_fallback_copy_buffers,
1060 .query_buffer_age = dri2_wl_query_buffer_age,
1061 .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
1062 .get_sync_values = dri2_fallback_get_sync_values,
1063 .get_dri_drawable = dri2_surface_get_dri_drawable,
1064 };
1065
1066 static const __DRIextension *dri2_loader_extensions[] = {
1067 &dri2_loader_extension.base,
1068 &image_loader_extension.base,
1069 &image_lookup_extension.base,
1070 &use_invalidate.base,
1071 NULL,
1072 };
1073
1074 static const __DRIextension *image_loader_extensions[] = {
1075 &image_loader_extension.base,
1076 &image_lookup_extension.base,
1077 &use_invalidate.base,
1078 NULL,
1079 };
1080
1081 static EGLBoolean
dri2_wl_add_configs_for_visuals(_EGLDriver * drv,_EGLDisplay * disp)1082 dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
1083 {
1084 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1085 static const struct {
1086 const char *format_name;
1087 int has_format;
1088 unsigned int rgba_masks[4];
1089 } visuals[] = {
1090 { "XRGB8888", HAS_XRGB8888, { 0xff0000, 0xff00, 0x00ff, 0xff000000 } },
1091 { "ARGB8888", HAS_ARGB8888, { 0xff0000, 0xff00, 0x00ff, 0 } },
1092 { "RGB565", HAS_RGB565, { 0x00f800, 0x07e0, 0x001f, 0 } },
1093 };
1094 unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
1095 unsigned int count, i, j;
1096
1097 count = 0;
1098 for (i = 0; dri2_dpy->driver_configs[i]; i++) {
1099 for (j = 0; j < ARRAY_SIZE(visuals); j++) {
1100 struct dri2_egl_config *dri2_conf;
1101
1102 if (!(dri2_dpy->formats & visuals[j].has_format))
1103 continue;
1104
1105 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
1106 count + 1, EGL_WINDOW_BIT, NULL, visuals[j].rgba_masks);
1107 if (dri2_conf) {
1108 count++;
1109 format_count[j]++;
1110 }
1111 }
1112 }
1113
1114 for (i = 0; i < ARRAY_SIZE(format_count); i++) {
1115 if (!format_count[i]) {
1116 _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
1117 visuals[i].format_name);
1118 }
1119 }
1120
1121 return (count != 0);
1122 }
1123
1124 static EGLBoolean
dri2_initialize_wayland_drm(_EGLDriver * drv,_EGLDisplay * disp)1125 dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
1126 {
1127 struct dri2_egl_display *dri2_dpy;
1128
1129 loader_set_logger(_eglLog);
1130
1131 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1132 if (!dri2_dpy)
1133 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1134
1135 disp->DriverData = (void *) dri2_dpy;
1136 if (disp->PlatformDisplay == NULL) {
1137 dri2_dpy->wl_dpy = wl_display_connect(NULL);
1138 if (dri2_dpy->wl_dpy == NULL)
1139 goto cleanup_dpy;
1140 dri2_dpy->own_device = 1;
1141 } else {
1142 dri2_dpy->wl_dpy = disp->PlatformDisplay;
1143 }
1144
1145 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
1146
1147 dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
1148 if (dri2_dpy->wl_dpy_wrapper == NULL)
1149 goto cleanup_dpy_wrapper;
1150
1151 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
1152 dri2_dpy->wl_queue);
1153
1154 if (dri2_dpy->own_device)
1155 wl_display_dispatch_pending(dri2_dpy->wl_dpy);
1156
1157 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
1158 wl_registry_add_listener(dri2_dpy->wl_registry,
1159 ®istry_listener_drm, dri2_dpy);
1160 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
1161 goto cleanup_registry;
1162
1163 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
1164 goto cleanup_drm;
1165
1166 if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
1167 goto cleanup_fd;
1168
1169 dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
1170 &dri2_dpy->is_different_gpu);
1171 if (dri2_dpy->is_different_gpu) {
1172 free(dri2_dpy->device_name);
1173 dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
1174 if (!dri2_dpy->device_name) {
1175 _eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
1176 "for requested GPU");
1177 goto cleanup_fd;
1178 }
1179 }
1180
1181 /* we have to do the check now, because loader_get_user_preferred_fd
1182 * will return a render-node when the requested gpu is different
1183 * to the server, but also if the client asks for the same gpu than
1184 * the server by requesting its pci-id */
1185 dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
1186
1187 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
1188 if (dri2_dpy->driver_name == NULL) {
1189 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
1190 goto cleanup_fd;
1191 }
1192
1193 if (!dri2_load_driver(disp))
1194 goto cleanup_driver_name;
1195
1196 /* render nodes cannot use Gem names, and thus do not support
1197 * the __DRI_DRI2_LOADER extension */
1198 if (!dri2_dpy->is_render_node)
1199 dri2_dpy->loader_extensions = dri2_loader_extensions;
1200 else
1201 dri2_dpy->loader_extensions = image_loader_extensions;
1202
1203 if (!dri2_create_screen(disp))
1204 goto cleanup_driver;
1205
1206 dri2_wl_setup_swap_interval(dri2_dpy);
1207
1208 /* To use Prime, we must have _DRI_IMAGE v7 at least.
1209 * createImageFromFds support indicates that Prime export/import
1210 * is supported by the driver. Fall back to
1211 * gem names if we don't have Prime support. */
1212
1213 if (dri2_dpy->image->base.version < 7 ||
1214 dri2_dpy->image->createImageFromFds == NULL)
1215 dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
1216
1217 /* We cannot use Gem names with render-nodes, only prime fds (dma-buf).
1218 * The server needs to accept them */
1219 if (dri2_dpy->is_render_node &&
1220 !(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {
1221 _eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
1222 goto cleanup_screen;
1223 }
1224
1225 if (dri2_dpy->is_different_gpu &&
1226 (dri2_dpy->image->base.version < 9 ||
1227 dri2_dpy->image->blitImage == NULL)) {
1228 _eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "
1229 "Image extension in the driver is not "
1230 "compatible. Version 9 or later and blitImage() "
1231 "are required");
1232 goto cleanup_screen;
1233 }
1234
1235 if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
1236 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
1237 goto cleanup_screen;
1238 }
1239
1240 dri2_set_WL_bind_wayland_display(drv, disp);
1241 /* When cannot convert EGLImage to wl_buffer when on a different gpu,
1242 * because the buffer of the EGLImage has likely a tiling mode the server
1243 * gpu won't support. These is no way to check for now. Thus do not support the
1244 * extension */
1245 if (!dri2_dpy->is_different_gpu) {
1246 disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
1247 } else {
1248 dri2_wl_display_vtbl.create_wayland_buffer_from_image =
1249 dri2_fallback_create_wayland_buffer_from_image;
1250 }
1251 disp->Extensions.EXT_buffer_age = EGL_TRUE;
1252
1253 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1254
1255 /* Fill vtbl last to prevent accidentally calling virtual function during
1256 * initialization.
1257 */
1258 dri2_dpy->vtbl = &dri2_wl_display_vtbl;
1259
1260 return EGL_TRUE;
1261
1262 cleanup_screen:
1263 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1264 cleanup_driver:
1265 dlclose(dri2_dpy->driver);
1266 cleanup_driver_name:
1267 free(dri2_dpy->driver_name);
1268 cleanup_fd:
1269 close(dri2_dpy->fd);
1270 cleanup_drm:
1271 free(dri2_dpy->device_name);
1272 wl_drm_destroy(dri2_dpy->wl_drm);
1273 cleanup_registry:
1274 wl_registry_destroy(dri2_dpy->wl_registry);
1275 wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
1276 cleanup_dpy_wrapper:
1277 wl_event_queue_destroy(dri2_dpy->wl_queue);
1278 if (disp->PlatformDisplay == NULL)
1279 wl_display_disconnect(dri2_dpy->wl_dpy);
1280 cleanup_dpy:
1281 free(dri2_dpy);
1282 disp->DriverData = NULL;
1283
1284 return EGL_FALSE;
1285 }
1286
1287 static int
dri2_wl_swrast_get_stride_for_format(int format,int w)1288 dri2_wl_swrast_get_stride_for_format(int format, int w)
1289 {
1290 if (format == WL_SHM_FORMAT_RGB565)
1291 return 2 * w;
1292 else /* ARGB8888 || XRGB8888 */
1293 return 4 * w;
1294 }
1295
1296 /*
1297 * Taken from weston shared/os-compatibility.c
1298 */
1299
1300 #ifndef HAVE_MKOSTEMP
1301
1302 static int
set_cloexec_or_close(int fd)1303 set_cloexec_or_close(int fd)
1304 {
1305 long flags;
1306
1307 if (fd == -1)
1308 return -1;
1309
1310 flags = fcntl(fd, F_GETFD);
1311 if (flags == -1)
1312 goto err;
1313
1314 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
1315 goto err;
1316
1317 return fd;
1318
1319 err:
1320 close(fd);
1321 return -1;
1322 }
1323
1324 #endif
1325
1326 /*
1327 * Taken from weston shared/os-compatibility.c
1328 */
1329
1330 static int
create_tmpfile_cloexec(char * tmpname)1331 create_tmpfile_cloexec(char *tmpname)
1332 {
1333 int fd;
1334
1335 #ifdef HAVE_MKOSTEMP
1336 fd = mkostemp(tmpname, O_CLOEXEC);
1337 if (fd >= 0)
1338 unlink(tmpname);
1339 #else
1340 fd = mkstemp(tmpname);
1341 if (fd >= 0) {
1342 fd = set_cloexec_or_close(fd);
1343 unlink(tmpname);
1344 }
1345 #endif
1346
1347 return fd;
1348 }
1349
1350 /*
1351 * Taken from weston shared/os-compatibility.c
1352 *
1353 * Create a new, unique, anonymous file of the given size, and
1354 * return the file descriptor for it. The file descriptor is set
1355 * CLOEXEC. The file is immediately suitable for mmap()'ing
1356 * the given size at offset zero.
1357 *
1358 * The file should not have a permanent backing store like a disk,
1359 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
1360 *
1361 * The file name is deleted from the file system.
1362 *
1363 * The file is suitable for buffer sharing between processes by
1364 * transmitting the file descriptor over Unix sockets using the
1365 * SCM_RIGHTS methods.
1366 *
1367 * If the C library implements posix_fallocate(), it is used to
1368 * guarantee that disk space is available for the file at the
1369 * given size. If disk space is insufficent, errno is set to ENOSPC.
1370 * If posix_fallocate() is not supported, program may receive
1371 * SIGBUS on accessing mmap()'ed file contents instead.
1372 */
1373 static int
os_create_anonymous_file(off_t size)1374 os_create_anonymous_file(off_t size)
1375 {
1376 static const char template[] = "/mesa-shared-XXXXXX";
1377 const char *path;
1378 char *name;
1379 int fd;
1380 int ret;
1381
1382 path = getenv("XDG_RUNTIME_DIR");
1383 if (!path) {
1384 errno = ENOENT;
1385 return -1;
1386 }
1387
1388 name = malloc(strlen(path) + sizeof(template));
1389 if (!name)
1390 return -1;
1391
1392 strcpy(name, path);
1393 strcat(name, template);
1394
1395 fd = create_tmpfile_cloexec(name);
1396
1397 free(name);
1398
1399 if (fd < 0)
1400 return -1;
1401
1402 ret = ftruncate(fd, size);
1403 if (ret < 0) {
1404 close(fd);
1405 return -1;
1406 }
1407
1408 return fd;
1409 }
1410
1411
1412 static EGLBoolean
dri2_wl_swrast_allocate_buffer(struct dri2_egl_display * dri2_dpy,int format,int w,int h,void ** data,int * size,struct wl_buffer ** buffer)1413 dri2_wl_swrast_allocate_buffer(struct dri2_egl_display *dri2_dpy,
1414 int format, int w, int h,
1415 void **data, int *size,
1416 struct wl_buffer **buffer)
1417 {
1418 struct wl_shm_pool *pool;
1419 int fd, stride, size_map;
1420 void *data_map;
1421
1422 stride = dri2_wl_swrast_get_stride_for_format(format, w);
1423 size_map = h * stride;
1424
1425 /* Create a sharable buffer */
1426 fd = os_create_anonymous_file(size_map);
1427 if (fd < 0)
1428 return EGL_FALSE;
1429
1430 data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1431 if (data_map == MAP_FAILED) {
1432 close(fd);
1433 return EGL_FALSE;
1434 }
1435
1436 /* Share it in a wl_buffer */
1437 pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
1438 *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
1439 wl_shm_pool_destroy(pool);
1440 close(fd);
1441
1442 *data = data_map;
1443 *size = size_map;
1444 return EGL_TRUE;
1445 }
1446
1447 static int
swrast_update_buffers(struct dri2_egl_surface * dri2_surf)1448 swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
1449 {
1450 struct dri2_egl_display *dri2_dpy =
1451 dri2_egl_display(dri2_surf->base.Resource.Display);
1452 int i;
1453
1454 /* we need to do the following operations only once per frame */
1455 if (dri2_surf->back)
1456 return 0;
1457
1458 if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
1459 dri2_surf->base.Height != dri2_surf->wl_win->height) {
1460
1461 dri2_wl_release_buffers(dri2_surf);
1462
1463 dri2_surf->base.Width = dri2_surf->wl_win->width;
1464 dri2_surf->base.Height = dri2_surf->wl_win->height;
1465 dri2_surf->dx = dri2_surf->wl_win->dx;
1466 dri2_surf->dy = dri2_surf->wl_win->dy;
1467 dri2_surf->current = NULL;
1468 }
1469
1470 /* find back buffer */
1471
1472 /* There might be a buffer release already queued that wasn't processed */
1473 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
1474
1475 /* try get free buffer already created */
1476 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1477 if (!dri2_surf->color_buffers[i].locked &&
1478 dri2_surf->color_buffers[i].wl_buffer) {
1479 dri2_surf->back = &dri2_surf->color_buffers[i];
1480 break;
1481 }
1482 }
1483
1484 /* else choose any another free location */
1485 if (!dri2_surf->back) {
1486 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1487 if (!dri2_surf->color_buffers[i].locked) {
1488 dri2_surf->back = &dri2_surf->color_buffers[i];
1489 if (!dri2_wl_swrast_allocate_buffer(dri2_dpy,
1490 dri2_surf->format,
1491 dri2_surf->base.Width,
1492 dri2_surf->base.Height,
1493 &dri2_surf->back->data,
1494 &dri2_surf->back->data_size,
1495 &dri2_surf->back->wl_buffer)) {
1496 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
1497 return -1;
1498 }
1499 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->back->wl_buffer,
1500 dri2_dpy->wl_queue);
1501 wl_buffer_add_listener(dri2_surf->back->wl_buffer,
1502 &wl_buffer_listener, dri2_surf);
1503 break;
1504 }
1505 }
1506 }
1507
1508 if (!dri2_surf->back) {
1509 _eglError(EGL_BAD_ALLOC, "failed to find free buffer");
1510 return -1;
1511 }
1512
1513 dri2_surf->back->locked = 1;
1514
1515 /* If we have an extra unlocked buffer at this point, we had to do triple
1516 * buffering for a while, but now can go back to just double buffering.
1517 * That means we can free any unlocked buffer now. */
1518 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1519 if (!dri2_surf->color_buffers[i].locked &&
1520 dri2_surf->color_buffers[i].wl_buffer) {
1521 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
1522 munmap(dri2_surf->color_buffers[i].data,
1523 dri2_surf->color_buffers[i].data_size);
1524 dri2_surf->color_buffers[i].wl_buffer = NULL;
1525 dri2_surf->color_buffers[i].data = NULL;
1526 }
1527 }
1528
1529 return 0;
1530 }
1531
1532 static void*
dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface * dri2_surf)1533 dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
1534 {
1535 /* if there has been a resize: */
1536 if (!dri2_surf->current)
1537 return NULL;
1538
1539 return dri2_surf->current->data;
1540 }
1541
1542 static void*
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface * dri2_surf)1543 dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
1544 {
1545 assert(dri2_surf->back);
1546 return dri2_surf->back->data;
1547 }
1548
1549 static void
dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface * dri2_surf)1550 dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
1551 {
1552 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
1553
1554 while (dri2_surf->throttle_callback != NULL)
1555 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
1556 dri2_dpy->wl_queue) == -1)
1557 return;
1558
1559 if (dri2_surf->base.SwapInterval > 0) {
1560 dri2_surf->throttle_callback =
1561 wl_surface_frame(dri2_surf->wl_win->surface);
1562 wl_callback_add_listener(dri2_surf->throttle_callback,
1563 &throttle_listener, dri2_surf);
1564 wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
1565 dri2_dpy->wl_queue);
1566 }
1567
1568 dri2_surf->current = dri2_surf->back;
1569 dri2_surf->back = NULL;
1570
1571 wl_surface_attach(dri2_surf->wl_win->surface,
1572 dri2_surf->current->wl_buffer,
1573 dri2_surf->dx, dri2_surf->dy);
1574
1575 dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
1576 dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
1577 /* reset resize growing parameters */
1578 dri2_surf->dx = 0;
1579 dri2_surf->dy = 0;
1580
1581 wl_surface_damage(dri2_surf->wl_win->surface,
1582 0, 0, INT32_MAX, INT32_MAX);
1583 wl_surface_commit(dri2_surf->wl_win->surface);
1584
1585 /* If we're not waiting for a frame callback then we'll at least throttle
1586 * to a sync callback so that we always give a chance for the compositor to
1587 * handle the commit and send a release event before checking for a free
1588 * buffer */
1589 if (dri2_surf->throttle_callback == NULL) {
1590 dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
1591 wl_callback_add_listener(dri2_surf->throttle_callback,
1592 &throttle_listener, dri2_surf);
1593 }
1594
1595 wl_display_flush(dri2_dpy->wl_dpy);
1596 }
1597
1598 static void
dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)1599 dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,
1600 int *x, int *y, int *w, int *h,
1601 void *loaderPrivate)
1602 {
1603 struct dri2_egl_surface *dri2_surf = loaderPrivate;
1604
1605 (void) swrast_update_buffers(dri2_surf);
1606 *x = 0;
1607 *y = 0;
1608 *w = dri2_surf->base.Width;
1609 *h = dri2_surf->base.Height;
1610 }
1611
1612 static void
dri2_wl_swrast_get_image(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)1613 dri2_wl_swrast_get_image(__DRIdrawable * read,
1614 int x, int y, int w, int h,
1615 char *data, void *loaderPrivate)
1616 {
1617 struct dri2_egl_surface *dri2_surf = loaderPrivate;
1618 int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1619 int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
1620 int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
1621 int dst_stride = copy_width;
1622 char *src, *dst;
1623
1624 src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);
1625 if (!src) {
1626 memset(data, 0, copy_width * h);
1627 return;
1628 }
1629
1630 assert(data != src);
1631 assert(copy_width <= src_stride);
1632
1633 src += x_offset;
1634 src += y * src_stride;
1635 dst = data;
1636
1637 if (copy_width > src_stride-x_offset)
1638 copy_width = src_stride-x_offset;
1639 if (h > dri2_surf->base.Height-y)
1640 h = dri2_surf->base.Height-y;
1641
1642 for (; h>0; h--) {
1643 memcpy(dst, src, copy_width);
1644 src += src_stride;
1645 dst += dst_stride;
1646 }
1647 }
1648
1649 static void
dri2_wl_swrast_put_image2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)1650 dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,
1651 int x, int y, int w, int h, int stride,
1652 char *data, void *loaderPrivate)
1653 {
1654 struct dri2_egl_surface *dri2_surf = loaderPrivate;
1655 int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1656 int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
1657 int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
1658 char *src, *dst;
1659
1660 assert(copy_width <= stride);
1661
1662 (void) swrast_update_buffers(dri2_surf);
1663 dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
1664
1665 /* partial copy, copy old content */
1666 if (copy_width < dst_stride)
1667 dri2_wl_swrast_get_image(draw, 0, 0,
1668 dri2_surf->base.Width, dri2_surf->base.Height,
1669 dst, loaderPrivate);
1670
1671 dst += x_offset;
1672 dst += y * dst_stride;
1673
1674 src = data;
1675
1676 /* drivers expect we do these checks (and some rely on it) */
1677 if (copy_width > dst_stride-x_offset)
1678 copy_width = dst_stride-x_offset;
1679 if (h > dri2_surf->base.Height-y)
1680 h = dri2_surf->base.Height-y;
1681
1682 for (; h>0; h--) {
1683 memcpy(dst, src, copy_width);
1684 src += stride;
1685 dst += dst_stride;
1686 }
1687 dri2_wl_swrast_commit_backbuffer(dri2_surf);
1688 }
1689
1690 static void
dri2_wl_swrast_put_image(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)1691 dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,
1692 int x, int y, int w, int h,
1693 char *data, void *loaderPrivate)
1694 {
1695 struct dri2_egl_surface *dri2_surf = loaderPrivate;
1696 int stride;
1697
1698 stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1699 dri2_wl_swrast_put_image2(draw, op, x, y, w, h,
1700 stride, data, loaderPrivate);
1701 }
1702
1703 static EGLBoolean
dri2_wl_swrast_swap_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw)1704 dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
1705 {
1706 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1707 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
1708
1709 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
1710 return EGL_TRUE;
1711 }
1712
1713 static void
shm_handle_format(void * data,struct wl_shm * shm,uint32_t format)1714 shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
1715 {
1716 struct dri2_egl_display *dri2_dpy = data;
1717
1718 switch (format) {
1719 case WL_SHM_FORMAT_ARGB8888:
1720 dri2_dpy->formats |= HAS_ARGB8888;
1721 break;
1722 case WL_SHM_FORMAT_XRGB8888:
1723 dri2_dpy->formats |= HAS_XRGB8888;
1724 break;
1725 case WL_SHM_FORMAT_RGB565:
1726 dri2_dpy->formats |= HAS_RGB565;
1727 break;
1728 }
1729 }
1730
1731 static const struct wl_shm_listener shm_listener = {
1732 .format = shm_handle_format
1733 };
1734
1735 static void
registry_handle_global_swrast(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)1736 registry_handle_global_swrast(void *data, struct wl_registry *registry, uint32_t name,
1737 const char *interface, uint32_t version)
1738 {
1739 struct dri2_egl_display *dri2_dpy = data;
1740
1741 if (strcmp(interface, "wl_shm") == 0) {
1742 dri2_dpy->wl_shm =
1743 wl_registry_bind(registry, name, &wl_shm_interface, 1);
1744 wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);
1745 }
1746 }
1747
1748 static const struct wl_registry_listener registry_listener_swrast = {
1749 .global = registry_handle_global_swrast,
1750 .global_remove = registry_handle_global_remove
1751 };
1752
1753 static struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
1754 .authenticate = NULL,
1755 .create_window_surface = dri2_wl_create_window_surface,
1756 .create_pixmap_surface = dri2_wl_create_pixmap_surface,
1757 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
1758 .destroy_surface = dri2_wl_destroy_surface,
1759 .create_image = dri2_fallback_create_image_khr,
1760 .swap_interval = dri2_wl_swap_interval,
1761 .swap_buffers = dri2_wl_swrast_swap_buffers,
1762 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
1763 .swap_buffers_region = dri2_fallback_swap_buffers_region,
1764 .post_sub_buffer = dri2_fallback_post_sub_buffer,
1765 .copy_buffers = dri2_fallback_copy_buffers,
1766 .query_buffer_age = dri2_fallback_query_buffer_age,
1767 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1768 .get_sync_values = dri2_fallback_get_sync_values,
1769 .get_dri_drawable = dri2_surface_get_dri_drawable,
1770 };
1771
1772 static const __DRIswrastLoaderExtension swrast_loader_extension = {
1773 .base = { __DRI_SWRAST_LOADER, 2 },
1774
1775 .getDrawableInfo = dri2_wl_swrast_get_drawable_info,
1776 .putImage = dri2_wl_swrast_put_image,
1777 .getImage = dri2_wl_swrast_get_image,
1778 .putImage2 = dri2_wl_swrast_put_image2,
1779 };
1780
1781 static const __DRIextension *swrast_loader_extensions[] = {
1782 &swrast_loader_extension.base,
1783 NULL,
1784 };
1785
1786 static EGLBoolean
dri2_initialize_wayland_swrast(_EGLDriver * drv,_EGLDisplay * disp)1787 dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
1788 {
1789 struct dri2_egl_display *dri2_dpy;
1790
1791 loader_set_logger(_eglLog);
1792
1793 dri2_dpy = calloc(1, sizeof *dri2_dpy);
1794 if (!dri2_dpy)
1795 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1796
1797 disp->DriverData = (void *) dri2_dpy;
1798 if (disp->PlatformDisplay == NULL) {
1799 dri2_dpy->wl_dpy = wl_display_connect(NULL);
1800 if (dri2_dpy->wl_dpy == NULL)
1801 goto cleanup_dpy;
1802 dri2_dpy->own_device = 1;
1803 } else {
1804 dri2_dpy->wl_dpy = disp->PlatformDisplay;
1805 }
1806
1807 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
1808
1809 dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
1810 if (dri2_dpy->wl_dpy_wrapper == NULL)
1811 goto cleanup_dpy_wrapper;
1812
1813 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
1814 dri2_dpy->wl_queue);
1815
1816 if (dri2_dpy->own_device)
1817 wl_display_dispatch_pending(dri2_dpy->wl_dpy);
1818
1819 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
1820 wl_registry_add_listener(dri2_dpy->wl_registry,
1821 ®istry_listener_swrast, dri2_dpy);
1822
1823 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
1824 goto cleanup_registry;
1825
1826 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0)
1827 goto cleanup_shm;
1828
1829 dri2_dpy->fd = -1;
1830 dri2_dpy->driver_name = strdup("swrast");
1831 if (!dri2_load_driver_swrast(disp))
1832 goto cleanup_shm;
1833
1834 dri2_dpy->loader_extensions = swrast_loader_extensions;
1835
1836 if (!dri2_create_screen(disp))
1837 goto cleanup_driver;
1838
1839 dri2_wl_setup_swap_interval(dri2_dpy);
1840
1841 if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
1842 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
1843 goto cleanup_screen;
1844 }
1845
1846 /* Fill vtbl last to prevent accidentally calling virtual function during
1847 * initialization.
1848 */
1849 dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
1850
1851 return EGL_TRUE;
1852
1853 cleanup_screen:
1854 dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1855 cleanup_driver:
1856 dlclose(dri2_dpy->driver);
1857 cleanup_shm:
1858 wl_shm_destroy(dri2_dpy->wl_shm);
1859 cleanup_registry:
1860 wl_registry_destroy(dri2_dpy->wl_registry);
1861 wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
1862 cleanup_dpy_wrapper:
1863 wl_event_queue_destroy(dri2_dpy->wl_queue);
1864 if (disp->PlatformDisplay == NULL)
1865 wl_display_disconnect(dri2_dpy->wl_dpy);
1866 cleanup_dpy:
1867 free(dri2_dpy);
1868 disp->DriverData = NULL;
1869
1870 return EGL_FALSE;
1871 }
1872
1873 EGLBoolean
dri2_initialize_wayland(_EGLDriver * drv,_EGLDisplay * disp)1874 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
1875 {
1876 EGLBoolean initialized = EGL_TRUE;
1877
1878 int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
1879
1880 if (hw_accel) {
1881 if (!dri2_initialize_wayland_drm(drv, disp)) {
1882 initialized = dri2_initialize_wayland_swrast(drv, disp);
1883 }
1884 } else {
1885 initialized = dri2_initialize_wayland_swrast(drv, disp);
1886 }
1887
1888 return initialized;
1889
1890 }
1891