• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                             &registry_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                             &registry_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