• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Kristian Høgsberg <krh@bitplanet.net>
26  */
27 
28 #include <dlfcn.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <stdbool.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 /* clang-format off */
39 #include <xcb/xcb.h>
40 #include <vulkan/vulkan_core.h>
41 #include <vulkan/vulkan_xcb.h>
42 /* clang-format on */
43 #ifdef HAVE_LIBDRM
44 #include <xf86drm.h>
45 #endif
46 #include "util/bitscan.h"
47 #include "util/macros.h"
48 #include "util/u_debug.h"
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 
52 #include "kopper_interface.h"
53 #include "loader.h"
54 #include "platform_x11.h"
55 
56 #ifdef HAVE_DRI3
57 #include "platform_x11_dri3.h"
58 #endif
59 
60 static EGLBoolean
61 dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval);
62 
63 static void
swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,struct dri2_egl_surface * dri2_surf)64 swrastCreateDrawable(struct dri2_egl_display *dri2_dpy,
65                      struct dri2_egl_surface *dri2_surf)
66 {
67    uint32_t mask;
68    const uint32_t function = GXcopy;
69    uint32_t valgc[2];
70 
71    /* create GC's */
72    dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
73    mask = XCB_GC_FUNCTION;
74    xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask,
75                  &function);
76 
77    dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
78    mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
79    valgc[0] = function;
80    valgc[1] = False;
81    xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask,
82                  valgc);
83    switch (dri2_surf->depth) {
84    case 32:
85    case 30:
86    case 24:
87       dri2_surf->bytes_per_pixel = 4;
88       break;
89    case 16:
90       dri2_surf->bytes_per_pixel = 2;
91       break;
92    case 8:
93       dri2_surf->bytes_per_pixel = 1;
94       break;
95    case 0:
96       dri2_surf->bytes_per_pixel = 0;
97       break;
98    default:
99       _eglLog(_EGL_WARNING, "unsupported depth %d", dri2_surf->depth);
100    }
101 }
102 
103 static void
swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,struct dri2_egl_surface * dri2_surf)104 swrastDestroyDrawable(struct dri2_egl_display *dri2_dpy,
105                       struct dri2_egl_surface *dri2_surf)
106 {
107    xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
108    xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
109 }
110 
111 static bool
x11_get_drawable_info(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)112 x11_get_drawable_info(__DRIdrawable *draw, int *x, int *y, int *w, int *h,
113                       void *loaderPrivate)
114 {
115    struct dri2_egl_surface *dri2_surf = loaderPrivate;
116    struct dri2_egl_display *dri2_dpy =
117       dri2_egl_display(dri2_surf->base.Resource.Display);
118 
119    xcb_get_geometry_cookie_t cookie;
120    xcb_get_geometry_reply_t *reply;
121    xcb_generic_error_t *error;
122    bool ret;
123 
124    cookie = xcb_get_geometry(dri2_dpy->conn, dri2_surf->drawable);
125    reply = xcb_get_geometry_reply(dri2_dpy->conn, cookie, &error);
126    if (reply == NULL)
127       return false;
128 
129    if (error != NULL) {
130       ret = false;
131       _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
132       free(error);
133    } else {
134       *x = reply->x;
135       *y = reply->y;
136       *w = reply->width;
137       *h = reply->height;
138       ret = true;
139    }
140    free(reply);
141    return ret;
142 }
143 
144 static void
swrastGetDrawableInfo(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)145 swrastGetDrawableInfo(__DRIdrawable *draw, int *x, int *y, int *w, int *h,
146                       void *loaderPrivate)
147 {
148    *x = *y = *w = *h = 0;
149    x11_get_drawable_info(draw, x, y, w, h, loaderPrivate);
150 }
151 
152 static void
swrastPutImage(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)153 swrastPutImage(__DRIdrawable *draw, int op, int x, int y, int w, int h,
154                char *data, void *loaderPrivate)
155 {
156    struct dri2_egl_surface *dri2_surf = loaderPrivate;
157    struct dri2_egl_display *dri2_dpy =
158       dri2_egl_display(dri2_surf->base.Resource.Display);
159    size_t hdr_len = sizeof(xcb_put_image_request_t);
160    int stride_b = dri2_surf->bytes_per_pixel * w;
161    size_t size = (hdr_len + stride_b * h) >> 2;
162    uint64_t max_req_len = xcb_get_maximum_request_length(dri2_dpy->conn);
163 
164    xcb_gcontext_t gc;
165    xcb_void_cookie_t cookie;
166    switch (op) {
167    case __DRI_SWRAST_IMAGE_OP_DRAW:
168       gc = dri2_surf->gc;
169       break;
170    case __DRI_SWRAST_IMAGE_OP_SWAP:
171       gc = dri2_surf->swapgc;
172       break;
173    default:
174       return;
175    }
176 
177    if (size < max_req_len) {
178       cookie = xcb_put_image(
179          dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable, gc, w,
180          h, x, y, 0, dri2_surf->depth, h * stride_b, (const uint8_t *)data);
181       xcb_discard_reply(dri2_dpy->conn, cookie.sequence);
182    } else {
183       int num_lines = ((max_req_len << 2) - hdr_len) / stride_b;
184       int y_start = 0;
185       int y_todo = h;
186       while (y_todo) {
187          int this_lines = MIN2(num_lines, y_todo);
188          cookie =
189             xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
190                           dri2_surf->drawable, gc, w, this_lines, x, y_start, 0,
191                           dri2_surf->depth, this_lines * stride_b,
192                           ((const uint8_t *)data + y_start * stride_b));
193          xcb_discard_reply(dri2_dpy->conn, cookie.sequence);
194          y_start += this_lines;
195          y_todo -= this_lines;
196       }
197    }
198 }
199 
200 static void
swrastGetImage(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)201 swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data,
202                void *loaderPrivate)
203 {
204    struct dri2_egl_surface *dri2_surf = loaderPrivate;
205    struct dri2_egl_display *dri2_dpy =
206       dri2_egl_display(dri2_surf->base.Resource.Display);
207 
208    xcb_get_image_cookie_t cookie;
209    xcb_get_image_reply_t *reply;
210    xcb_generic_error_t *error;
211 
212    cookie = xcb_get_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
213                           dri2_surf->drawable, x, y, w, h, ~0);
214    reply = xcb_get_image_reply(dri2_dpy->conn, cookie, &error);
215    if (reply == NULL)
216       return;
217 
218    if (error != NULL) {
219       _eglLog(_EGL_WARNING, "error in xcb_get_image");
220       free(error);
221    } else {
222       uint32_t bytes = xcb_get_image_data_length(reply);
223       uint8_t *idata = xcb_get_image_data(reply);
224       memcpy(data, idata, bytes);
225    }
226    free(reply);
227 }
228 
229 static xcb_screen_t *
get_xcb_screen(xcb_screen_iterator_t iter,int screen)230 get_xcb_screen(xcb_screen_iterator_t iter, int screen)
231 {
232    for (; iter.rem; --screen, xcb_screen_next(&iter))
233       if (screen == 0)
234          return iter.data;
235 
236    return NULL;
237 }
238 
239 static xcb_visualtype_t *
get_xcb_visualtype_for_depth(struct dri2_egl_display * dri2_dpy,int depth)240 get_xcb_visualtype_for_depth(struct dri2_egl_display *dri2_dpy, int depth)
241 {
242    xcb_visualtype_iterator_t visual_iter;
243    xcb_screen_t *screen = dri2_dpy->screen;
244    xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen);
245 
246    for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
247       if (depth_iter.data->depth != depth)
248          continue;
249 
250       visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
251       if (visual_iter.rem)
252          return visual_iter.data;
253    }
254 
255    return NULL;
256 }
257 
258 /* Get red channel mask for given depth. */
259 unsigned int
dri2_x11_get_red_mask_for_depth(struct dri2_egl_display * dri2_dpy,int depth)260 dri2_x11_get_red_mask_for_depth(struct dri2_egl_display *dri2_dpy, int depth)
261 {
262    xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(dri2_dpy, depth);
263 
264    if (visual)
265       return visual->red_mask;
266 
267    return 0;
268 }
269 
270 /**
271  * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
272  */
273 static _EGLSurface *
dri2_x11_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)274 dri2_x11_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
275                         void *native_surface, const EGLint *attrib_list)
276 {
277    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
278    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
279    struct dri2_egl_surface *dri2_surf;
280    xcb_get_geometry_cookie_t cookie;
281    xcb_get_geometry_reply_t *reply;
282    xcb_generic_error_t *error;
283    const __DRIconfig *config;
284 
285    dri2_surf = calloc(1, sizeof *dri2_surf);
286    if (!dri2_surf) {
287       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
288       return NULL;
289    }
290 
291    if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
292                           false, native_surface))
293       goto cleanup_surf;
294 
295    dri2_surf->region = XCB_NONE;
296    if (type == EGL_PBUFFER_BIT) {
297       dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
298       xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, dri2_surf->drawable,
299                         dri2_dpy->screen->root, dri2_surf->base.Width,
300                         dri2_surf->base.Height);
301    } else {
302       STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
303       dri2_surf->drawable = (uintptr_t)native_surface;
304    }
305 
306    config = dri2_get_dri_config(dri2_conf, type, dri2_surf->base.GLColorspace);
307 
308    if (!config) {
309       _eglError(EGL_BAD_MATCH,
310                 "Unsupported surfacetype/colorspace configuration");
311       goto cleanup_pixmap;
312    }
313 
314    if (type != EGL_PBUFFER_BIT) {
315       cookie = xcb_get_geometry(dri2_dpy->conn, dri2_surf->drawable);
316       reply = xcb_get_geometry_reply(dri2_dpy->conn, cookie, &error);
317       if (error != NULL) {
318          if (error->error_code == BadAlloc)
319             _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
320          else if (type == EGL_WINDOW_BIT)
321             _eglError(EGL_BAD_NATIVE_WINDOW, "xcb_get_geometry");
322          else
323             _eglError(EGL_BAD_NATIVE_PIXMAP, "xcb_get_geometry");
324          free(error);
325          free(reply);
326          goto cleanup_dri_drawable;
327       } else if (reply == NULL) {
328          _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
329          goto cleanup_dri_drawable;
330       }
331 
332       dri2_surf->base.Width = reply->width;
333       dri2_surf->base.Height = reply->height;
334       dri2_surf->depth = reply->depth;
335       free(reply);
336    }
337 
338    if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
339       goto cleanup_pixmap;
340 
341    if (dri2_dpy->dri2) {
342       xcb_void_cookie_t cookie;
343       int conn_error;
344 
345       cookie =
346          xcb_dri2_create_drawable_checked(dri2_dpy->conn, dri2_surf->drawable);
347       error = xcb_request_check(dri2_dpy->conn, cookie);
348       conn_error = xcb_connection_has_error(dri2_dpy->conn);
349       if (conn_error || error != NULL) {
350          if (type == EGL_PBUFFER_BIT || conn_error ||
351              error->error_code == BadAlloc)
352             _eglError(EGL_BAD_ALLOC, "xcb_dri2_create_drawable_checked");
353          else if (type == EGL_WINDOW_BIT)
354             _eglError(EGL_BAD_NATIVE_WINDOW,
355                       "xcb_dri2_create_drawable_checked");
356          else
357             _eglError(EGL_BAD_NATIVE_PIXMAP,
358                       "xcb_dri2_create_drawable_checked");
359          free(error);
360          goto cleanup_dri_drawable;
361       }
362    } else {
363       if (type == EGL_PBUFFER_BIT) {
364          dri2_surf->depth = conf->BufferSize;
365       }
366       swrastCreateDrawable(dri2_dpy, dri2_surf);
367    }
368 
369    /* we always copy the back buffer to front */
370    dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
371 
372    return &dri2_surf->base;
373 
374 cleanup_dri_drawable:
375    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
376 cleanup_pixmap:
377    if (type == EGL_PBUFFER_BIT)
378       xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
379 cleanup_surf:
380    free(dri2_surf);
381 
382    return NULL;
383 }
384 
385 /**
386  * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
387  */
388 static _EGLSurface *
dri2_x11_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)389 dri2_x11_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
390                                void *native_window, const EGLint *attrib_list)
391 {
392    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
393    _EGLSurface *surf;
394 
395    surf = dri2_x11_create_surface(disp, EGL_WINDOW_BIT, conf, native_window,
396                                   attrib_list);
397    if (surf != NULL) {
398       /* When we first create the DRI2 drawable, its swap interval on the
399        * server side is 1.
400        */
401       surf->SwapInterval = 1;
402 
403       /* Override that with a driconf-set value. */
404       dri2_x11_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
405    }
406 
407    return surf;
408 }
409 
410 static _EGLSurface *
dri2_x11_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)411 dri2_x11_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
412                                void *native_pixmap, const EGLint *attrib_list)
413 {
414    return dri2_x11_create_surface(disp, EGL_PIXMAP_BIT, conf, native_pixmap,
415                                   attrib_list);
416 }
417 
418 static _EGLSurface *
dri2_x11_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)419 dri2_x11_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
420                                 const EGLint *attrib_list)
421 {
422    return dri2_x11_create_surface(disp, EGL_PBUFFER_BIT, conf, NULL,
423                                   attrib_list);
424 }
425 
426 static EGLBoolean
dri2_x11_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)427 dri2_x11_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
428 {
429    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
430    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
431 
432    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
433 
434    if (dri2_dpy->dri2) {
435       xcb_dri2_destroy_drawable(dri2_dpy->conn, dri2_surf->drawable);
436    } else {
437       assert(dri2_dpy->swrast);
438       swrastDestroyDrawable(dri2_dpy, dri2_surf);
439    }
440 
441    if (surf->Type == EGL_PBUFFER_BIT)
442       xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
443 
444    dri2_fini_surface(surf);
445    free(surf);
446 
447    return EGL_TRUE;
448 }
449 
450 /**
451  * Function utilizes swrastGetDrawableInfo to get surface
452  * geometry from x server and calls default query surface
453  * implementation that returns the updated values.
454  *
455  * In case of errors we still return values that we currently
456  * have.
457  */
458 static EGLBoolean
dri2_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)459 dri2_query_surface(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute,
460                    EGLint *value)
461 {
462    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
463    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
464    int x, y, w, h;
465 
466    __DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
467 
468    switch (attribute) {
469    case EGL_WIDTH:
470    case EGL_HEIGHT:
471       if (x11_get_drawable_info(drawable, &x, &y, &w, &h, dri2_surf)) {
472          bool changed = surf->Width != w || surf->Height != h;
473          surf->Width = w;
474          surf->Height = h;
475          if (changed && dri2_dpy->flush)
476             dri2_dpy->flush->invalidate(drawable);
477       }
478       break;
479    default:
480       break;
481    }
482    return _eglQuerySurface(disp, surf, attribute, value);
483 }
484 
485 /**
486  * Process list of buffer received from the server
487  *
488  * Processes the list of buffers received in a reply from the server to either
489  * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
490  */
491 static void
dri2_x11_process_buffers(struct dri2_egl_surface * dri2_surf,xcb_dri2_dri2_buffer_t * buffers,unsigned count)492 dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,
493                          xcb_dri2_dri2_buffer_t *buffers, unsigned count)
494 {
495    struct dri2_egl_display *dri2_dpy =
496       dri2_egl_display(dri2_surf->base.Resource.Display);
497    xcb_rectangle_t rectangle;
498 
499    dri2_surf->have_fake_front = false;
500 
501    /* This assumes the DRI2 buffer attachment tokens matches the
502     * __DRIbuffer tokens. */
503    for (unsigned i = 0; i < count; i++) {
504       dri2_surf->buffers[i].attachment = buffers[i].attachment;
505       dri2_surf->buffers[i].name = buffers[i].name;
506       dri2_surf->buffers[i].pitch = buffers[i].pitch;
507       dri2_surf->buffers[i].cpp = buffers[i].cpp;
508       dri2_surf->buffers[i].flags = buffers[i].flags;
509 
510       /* We only use the DRI drivers single buffer configs.  This
511        * means that if we try to render to a window, DRI2 will give us
512        * the fake front buffer, which we'll use as a back buffer.
513        * Note that EGL doesn't require that several clients rendering
514        * to the same window must see the same aux buffers. */
515       if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
516          dri2_surf->have_fake_front = true;
517    }
518 
519    if (dri2_surf->region != XCB_NONE)
520       xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
521 
522    rectangle.x = 0;
523    rectangle.y = 0;
524    rectangle.width = dri2_surf->base.Width;
525    rectangle.height = dri2_surf->base.Height;
526    dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
527    xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
528 }
529 
530 static __DRIbuffer *
dri2_x11_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)531 dri2_x11_get_buffers(__DRIdrawable *driDrawable, int *width, int *height,
532                      unsigned int *attachments, int count, int *out_count,
533                      void *loaderPrivate)
534 {
535    struct dri2_egl_surface *dri2_surf = loaderPrivate;
536    struct dri2_egl_display *dri2_dpy =
537       dri2_egl_display(dri2_surf->base.Resource.Display);
538    xcb_dri2_dri2_buffer_t *buffers;
539    xcb_dri2_get_buffers_reply_t *reply;
540    xcb_dri2_get_buffers_cookie_t cookie;
541 
542    (void)driDrawable;
543 
544    cookie = xcb_dri2_get_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
545                                            count, count, attachments);
546    reply = xcb_dri2_get_buffers_reply(dri2_dpy->conn, cookie, NULL);
547    if (reply == NULL)
548       return NULL;
549    buffers = xcb_dri2_get_buffers_buffers(reply);
550    if (buffers == NULL) {
551       free(reply);
552       return NULL;
553    }
554 
555    *out_count = reply->count;
556    dri2_surf->base.Width = *width = reply->width;
557    dri2_surf->base.Height = *height = reply->height;
558    dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
559 
560    free(reply);
561 
562    return dri2_surf->buffers;
563 }
564 
565 static __DRIbuffer *
dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)566 dri2_x11_get_buffers_with_format(__DRIdrawable *driDrawable, int *width,
567                                  int *height, unsigned int *attachments,
568                                  int count, int *out_count, void *loaderPrivate)
569 {
570    struct dri2_egl_surface *dri2_surf = loaderPrivate;
571    struct dri2_egl_display *dri2_dpy =
572       dri2_egl_display(dri2_surf->base.Resource.Display);
573    xcb_dri2_dri2_buffer_t *buffers;
574    xcb_dri2_get_buffers_with_format_reply_t *reply;
575    xcb_dri2_get_buffers_with_format_cookie_t cookie;
576    xcb_dri2_attach_format_t *format_attachments;
577 
578    (void)driDrawable;
579 
580    format_attachments = (xcb_dri2_attach_format_t *)attachments;
581    cookie = xcb_dri2_get_buffers_with_format_unchecked(
582       dri2_dpy->conn, dri2_surf->drawable, count, count, format_attachments);
583 
584    reply = xcb_dri2_get_buffers_with_format_reply(dri2_dpy->conn, cookie, NULL);
585    if (reply == NULL)
586       return NULL;
587 
588    buffers = xcb_dri2_get_buffers_with_format_buffers(reply);
589    dri2_surf->base.Width = *width = reply->width;
590    dri2_surf->base.Height = *height = reply->height;
591    *out_count = reply->count;
592    dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
593 
594    free(reply);
595 
596    return dri2_surf->buffers;
597 }
598 
599 static void
dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)600 dri2_x11_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
601 {
602    (void)driDrawable;
603 
604    /* FIXME: Does EGL support front buffer rendering at all? */
605 
606 #if 0
607    struct dri2_egl_surface *dri2_surf = loaderPrivate;
608 
609    dri2WaitGL(dri2_surf);
610 #else
611    (void)loaderPrivate;
612 #endif
613 }
614 
615 static int
dri2_x11_do_authenticate(struct dri2_egl_display * dri2_dpy,uint32_t id)616 dri2_x11_do_authenticate(struct dri2_egl_display *dri2_dpy, uint32_t id)
617 {
618    xcb_dri2_authenticate_reply_t *authenticate;
619    xcb_dri2_authenticate_cookie_t authenticate_cookie;
620    int ret = 0;
621 
622    authenticate_cookie = xcb_dri2_authenticate_unchecked(
623       dri2_dpy->conn, dri2_dpy->screen->root, id);
624    authenticate =
625       xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
626 
627    if (authenticate == NULL || !authenticate->authenticated)
628       ret = -1;
629 
630    free(authenticate);
631 
632    return ret;
633 }
634 
635 static EGLBoolean
dri2_x11_local_authenticate(struct dri2_egl_display * dri2_dpy)636 dri2_x11_local_authenticate(struct dri2_egl_display *dri2_dpy)
637 {
638 #ifdef HAVE_LIBDRM
639    drm_magic_t magic;
640 
641    if (drmGetMagic(dri2_dpy->fd_render_gpu, &magic)) {
642       _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
643       return EGL_FALSE;
644    }
645 
646    if (dri2_x11_do_authenticate(dri2_dpy, magic) < 0) {
647       _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
648       return EGL_FALSE;
649    }
650 #endif
651    return EGL_TRUE;
652 }
653 
654 static EGLBoolean
dri2_x11_connect(struct dri2_egl_display * dri2_dpy)655 dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
656 {
657    xcb_xfixes_query_version_reply_t *xfixes_query;
658    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
659    xcb_dri2_query_version_reply_t *dri2_query;
660    xcb_dri2_query_version_cookie_t dri2_query_cookie;
661    xcb_dri2_connect_reply_t *connect;
662    xcb_dri2_connect_cookie_t connect_cookie;
663    xcb_generic_error_t *error;
664    char *driver_name, *loader_driver_name, *device_name;
665    const xcb_query_extension_reply_t *extension;
666 
667    xcb_prefetch_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
668    xcb_prefetch_extension_data(dri2_dpy->conn, &xcb_dri2_id);
669 
670    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
671    if (!(extension && extension->present))
672       return EGL_FALSE;
673 
674    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
675    if (!(extension && extension->present))
676       return EGL_FALSE;
677 
678    xfixes_query_cookie = xcb_xfixes_query_version(
679       dri2_dpy->conn, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
680 
681    dri2_query_cookie = xcb_dri2_query_version(
682       dri2_dpy->conn, XCB_DRI2_MAJOR_VERSION, XCB_DRI2_MINOR_VERSION);
683 
684    connect_cookie = xcb_dri2_connect_unchecked(
685       dri2_dpy->conn, dri2_dpy->screen->root, XCB_DRI2_DRIVER_TYPE_DRI);
686 
687    xfixes_query = xcb_xfixes_query_version_reply(dri2_dpy->conn,
688                                                  xfixes_query_cookie, &error);
689    if (xfixes_query == NULL || error != NULL ||
690        xfixes_query->major_version < 2) {
691       _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
692       free(error);
693       free(xfixes_query);
694       return EGL_FALSE;
695    }
696    free(xfixes_query);
697 
698    dri2_query =
699       xcb_dri2_query_version_reply(dri2_dpy->conn, dri2_query_cookie, &error);
700    if (dri2_query == NULL || error != NULL) {
701       _eglLog(_EGL_WARNING, "DRI2: failed to query version");
702       free(error);
703       free(dri2_query);
704       return EGL_FALSE;
705    }
706    dri2_dpy->dri2_major = dri2_query->major_version;
707    dri2_dpy->dri2_minor = dri2_query->minor_version;
708    free(dri2_query);
709 
710    connect = xcb_dri2_connect_reply(dri2_dpy->conn, connect_cookie, NULL);
711    if (connect == NULL ||
712        connect->driver_name_length + connect->device_name_length == 0) {
713       _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
714       free(connect);
715       return EGL_FALSE;
716    }
717 
718    device_name = xcb_dri2_connect_device_name(connect);
719 
720    dri2_dpy->fd_render_gpu = loader_open_device(device_name);
721    if (dri2_dpy->fd_render_gpu == -1) {
722       _eglLog(_EGL_WARNING, "DRI2: could not open %s (%s)", device_name,
723               strerror(errno));
724       free(connect);
725       return EGL_FALSE;
726    }
727 
728    if (!dri2_x11_local_authenticate(dri2_dpy)) {
729       close(dri2_dpy->fd_render_gpu);
730       free(connect);
731       return EGL_FALSE;
732    }
733 
734    driver_name = xcb_dri2_connect_driver_name(connect);
735 
736    /* If Mesa knows about the appropriate driver for this fd, then trust it.
737     * Otherwise, default to the server's value.
738     */
739    loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd_render_gpu);
740    if (loader_driver_name) {
741       dri2_dpy->driver_name = loader_driver_name;
742    } else {
743       dri2_dpy->driver_name =
744          strndup(driver_name, xcb_dri2_connect_driver_name_length(connect));
745    }
746 
747    if (!strcmp(dri2_dpy->driver_name, "zink")) {
748       close(dri2_dpy->fd_render_gpu);
749       return EGL_FALSE;
750    }
751 
752    if (dri2_dpy->driver_name == NULL) {
753       close(dri2_dpy->fd_render_gpu);
754       free(connect);
755       return EGL_FALSE;
756    }
757 
758 #ifdef HAVE_WAYLAND_PLATFORM
759    dri2_dpy->device_name =
760       strndup(device_name, xcb_dri2_connect_device_name_length(connect));
761 #endif
762 
763    free(connect);
764 
765    return EGL_TRUE;
766 }
767 
768 static int
dri2_x11_authenticate(_EGLDisplay * disp,uint32_t id)769 dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
770 {
771    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
772 
773    return dri2_x11_do_authenticate(dri2_dpy, id);
774 }
775 
776 static void
dri2_x11_add_configs_for_visuals(struct dri2_egl_display * dri2_dpy,_EGLDisplay * disp,bool supports_preserved)777 dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
778                                  _EGLDisplay *disp, bool supports_preserved)
779 {
780    xcb_depth_iterator_t d;
781    xcb_visualtype_t *visuals;
782    EGLint surface_type;
783 
784    d = xcb_screen_allowed_depths_iterator(dri2_dpy->screen);
785 
786    surface_type = EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT;
787 
788    if (supports_preserved)
789       surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
790 
791    while (d.rem > 0) {
792       EGLBoolean class_added[6] = {
793          0,
794       };
795 
796       visuals = xcb_depth_visuals(d.data);
797 
798       for (int i = 0; i < xcb_depth_visuals_length(d.data); i++) {
799          if (class_added[visuals[i]._class])
800             continue;
801 
802          class_added[visuals[i]._class] = EGL_TRUE;
803 
804          const int rgb_shifts[3] = {
805             ffs(visuals[i].red_mask) - 1,
806             ffs(visuals[i].green_mask) - 1,
807             ffs(visuals[i].blue_mask) - 1,
808          };
809 
810          const unsigned int rgb_sizes[3] = {
811             util_bitcount(visuals[i].red_mask),
812             util_bitcount(visuals[i].green_mask),
813             util_bitcount(visuals[i].blue_mask),
814          };
815 
816          const EGLint config_attrs[] = {
817             EGL_NATIVE_VISUAL_ID,
818             visuals[i].visual_id,
819             EGL_NATIVE_VISUAL_TYPE,
820             visuals[i]._class,
821             EGL_NONE,
822          };
823 
824          for (int j = 0; dri2_dpy->driver_configs[j]; j++) {
825             const __DRIconfig *config = dri2_dpy->driver_configs[j];
826             int shifts[4];
827             unsigned int sizes[4];
828 
829             dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
830 
831             if (memcmp(shifts, rgb_shifts, sizeof(rgb_shifts)) != 0 ||
832                 memcmp(sizes, rgb_sizes, sizeof(rgb_sizes)) != 0) {
833                continue;
834             }
835 
836             /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.
837              * Ditto for 30-bit RGB visuals to match a 32-bit RGBA EGLConfig.
838              * Otherwise it will only match a 32-bit RGBA visual.  On a
839              * composited window manager on X11, this will make all of the
840              * EGLConfigs with destination alpha get blended by the
841              * compositor.  This is probably not what the application
842              * wants... especially on drivers that only have 32-bit RGBA
843              * EGLConfigs! */
844             if (sizes[3] != 0) {
845                if (d.data->depth != 24 && d.data->depth != 30)
846                   continue;
847 
848                unsigned int rgba_mask =
849                   ~(visuals[i].red_mask | visuals[i].green_mask |
850                     visuals[i].blue_mask);
851 
852                if (shifts[3] != ffs(rgba_mask) - 1 ||
853                    sizes[3] != util_bitcount(rgba_mask))
854                   continue;
855             }
856 
857             dri2_add_config(disp, config, surface_type, config_attrs);
858          }
859       }
860 
861       xcb_depth_next(&d);
862    }
863 }
864 
865 static EGLBoolean
dri2_copy_region(_EGLDisplay * disp,_EGLSurface * draw,xcb_xfixes_region_t region)866 dri2_copy_region(_EGLDisplay *disp, _EGLSurface *draw,
867                  xcb_xfixes_region_t region)
868 {
869    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
870    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
871    enum xcb_dri2_attachment_t render_attachment;
872    xcb_dri2_copy_region_cookie_t cookie;
873 
874    /* No-op for a pixmap or pbuffer surface */
875    if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
876       return EGL_TRUE;
877 
878    assert(!dri2_dpy->kopper);
879    dri2_dpy->flush->flush(dri2_surf->dri_drawable);
880 
881    if (dri2_surf->have_fake_front)
882       render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
883    else
884       render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
885 
886    cookie = xcb_dri2_copy_region_unchecked(
887       dri2_dpy->conn, dri2_surf->drawable, region,
888       XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, render_attachment);
889    free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
890 
891    return EGL_TRUE;
892 }
893 
894 static int64_t
dri2_x11_swap_buffers_msc(_EGLDisplay * disp,_EGLSurface * draw,int64_t msc,int64_t divisor,int64_t remainder)895 dri2_x11_swap_buffers_msc(_EGLDisplay *disp, _EGLSurface *draw, int64_t msc,
896                           int64_t divisor, int64_t remainder)
897 {
898    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
899    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
900    uint32_t msc_hi = msc >> 32;
901    uint32_t msc_lo = msc & 0xffffffff;
902    uint32_t divisor_hi = divisor >> 32;
903    uint32_t divisor_lo = divisor & 0xffffffff;
904    uint32_t remainder_hi = remainder >> 32;
905    uint32_t remainder_lo = remainder & 0xffffffff;
906    xcb_dri2_swap_buffers_cookie_t cookie;
907    xcb_dri2_swap_buffers_reply_t *reply;
908    int64_t swap_count = -1;
909 
910    if (draw->SwapBehavior == EGL_BUFFER_PRESERVED ||
911        !dri2_dpy->swap_available) {
912       swap_count = dri2_copy_region(disp, draw, dri2_surf->region) ? 0 : -1;
913    } else {
914       dri2_flush_drawable_for_swapbuffers(disp, draw);
915 
916       cookie = xcb_dri2_swap_buffers_unchecked(
917          dri2_dpy->conn, dri2_surf->drawable, msc_hi, msc_lo, divisor_hi,
918          divisor_lo, remainder_hi, remainder_lo);
919 
920       reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
921 
922       if (reply) {
923          swap_count = combine_u32_into_u64(reply->swap_hi, reply->swap_lo);
924          free(reply);
925       }
926    }
927 
928    /* Since we aren't watching for the server's invalidate events like we're
929     * supposed to (due to XCB providing no mechanism for filtering the events
930     * the way xlib does), and SwapBuffers is a common cause of invalidate
931     * events, just shove one down to the driver, even though we haven't told
932     * the driver that we're the kind of loader that provides reliable
933     * invalidate events.  This causes the driver to request buffers again at
934     * its next draw, so that we get the correct buffers if a pageflip
935     * happened.  The driver should still be using the viewport hack to catch
936     * window resizes.
937     */
938    if (dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
939       dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
940 
941    return swap_count;
942 }
943 
944 static EGLBoolean
dri2_x11_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)945 dri2_x11_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
946 {
947    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
948    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
949 
950    if (dri2_dpy->kopper) {
951       /* From the EGL 1.4 spec (page 52):
952        *
953        *     "The contents of ancillary buffers are always undefined
954        *      after calling eglSwapBuffers."
955        */
956       dri2_dpy->kopper->swapBuffers(dri2_surf->dri_drawable,
957                                     __DRI2_FLUSH_INVALIDATE_ANCILLARY);
958       return EGL_TRUE;
959    } else if (!dri2_dpy->flush) {
960       /* aka the swrast path, which does the swap in the gallium driver. */
961       dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
962       return EGL_TRUE;
963    }
964 
965    if (dri2_x11_swap_buffers_msc(disp, draw, 0, 0, 0) == -1) {
966       /* Swap failed with a window drawable. */
967       return _eglError(EGL_BAD_NATIVE_WINDOW, __func__);
968    }
969    return EGL_TRUE;
970 }
971 
972 static EGLBoolean
dri2_x11_swap_buffers_region(_EGLDisplay * disp,_EGLSurface * draw,EGLint numRects,const EGLint * rects)973 dri2_x11_swap_buffers_region(_EGLDisplay *disp, _EGLSurface *draw,
974                              EGLint numRects, const EGLint *rects)
975 {
976    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
977    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
978    EGLBoolean ret;
979    xcb_xfixes_region_t region;
980    xcb_rectangle_t rectangles[16];
981 
982    if (numRects > (int)ARRAY_SIZE(rectangles))
983       return dri2_copy_region(disp, draw, dri2_surf->region);
984 
985    for (int i = 0; i < numRects; i++) {
986       rectangles[i].x = rects[i * 4];
987       rectangles[i].y =
988          dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
989       rectangles[i].width = rects[i * 4 + 2];
990       rectangles[i].height = rects[i * 4 + 3];
991    }
992 
993    region = xcb_generate_id(dri2_dpy->conn);
994    xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
995    ret = dri2_copy_region(disp, draw, region);
996    xcb_xfixes_destroy_region(dri2_dpy->conn, region);
997 
998    return ret;
999 }
1000 
1001 static EGLBoolean
dri2_x11_post_sub_buffer(_EGLDisplay * disp,_EGLSurface * draw,EGLint x,EGLint y,EGLint width,EGLint height)1002 dri2_x11_post_sub_buffer(_EGLDisplay *disp, _EGLSurface *draw, EGLint x,
1003                          EGLint y, EGLint width, EGLint height)
1004 {
1005    const EGLint rect[4] = {x, y, width, height};
1006 
1007    if (x < 0 || y < 0 || width < 0 || height < 0)
1008       _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
1009 
1010    return dri2_x11_swap_buffers_region(disp, draw, 1, rect);
1011 }
1012 
1013 static EGLBoolean
dri2_x11_swap_interval(_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)1014 dri2_x11_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
1015 {
1016    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1017    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1018 
1019    if (dri2_dpy->kopper) {
1020       dri2_dpy->kopper->setSwapInterval(dri2_surf->dri_drawable, interval);
1021       return EGL_TRUE;
1022    }
1023 
1024    if (dri2_dpy->swap_available)
1025       xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
1026 
1027    return EGL_TRUE;
1028 }
1029 
1030 static EGLBoolean
dri2_x11_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)1031 dri2_x11_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf,
1032                       void *native_pixmap_target)
1033 {
1034    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1035    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1036    xcb_gcontext_t gc;
1037    xcb_pixmap_t target;
1038 
1039    STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
1040    target = (uintptr_t)native_pixmap_target;
1041 
1042    if (dri2_dpy->flush)
1043       dri2_dpy->flush->flush(dri2_surf->dri_drawable);
1044    else {
1045       /* This should not be a swapBuffers, because it could present an
1046        * incomplete frame, and it could invalidate the back buffer if it's not
1047        * preserved.  We really do want to flush.  But it ends up working out
1048        * okay-ish on swrast because those aren't invalidating the back buffer on
1049        * swap.
1050        */
1051       dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
1052    }
1053 
1054    gc = xcb_generate_id(dri2_dpy->conn);
1055    xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
1056    xcb_copy_area(dri2_dpy->conn, dri2_surf->drawable, target, gc, 0, 0, 0, 0,
1057                  dri2_surf->base.Width, dri2_surf->base.Height);
1058    xcb_free_gc(dri2_dpy->conn, gc);
1059 
1060    return EGL_TRUE;
1061 }
1062 
1063 uint32_t
dri2_format_for_depth(struct dri2_egl_display * dri2_dpy,uint32_t depth)1064 dri2_format_for_depth(struct dri2_egl_display *dri2_dpy, uint32_t depth)
1065 {
1066    switch (depth) {
1067    case 16:
1068       return __DRI_IMAGE_FORMAT_RGB565;
1069    case 24:
1070       return __DRI_IMAGE_FORMAT_XRGB8888;
1071    case 30:
1072       /* Different preferred formats for different hw */
1073       if (dri2_x11_get_red_mask_for_depth(dri2_dpy, 30) == 0x3ff)
1074          return __DRI_IMAGE_FORMAT_XBGR2101010;
1075       else
1076          return __DRI_IMAGE_FORMAT_XRGB2101010;
1077    case 32:
1078       return __DRI_IMAGE_FORMAT_ARGB8888;
1079    default:
1080       return __DRI_IMAGE_FORMAT_NONE;
1081    }
1082 }
1083 
1084 static _EGLImage *
dri2_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)1085 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
1086                              EGLClientBuffer buffer, const EGLint *attr_list)
1087 {
1088    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1089    struct dri2_egl_image *dri2_img;
1090    unsigned int attachments[1];
1091    xcb_drawable_t drawable;
1092    xcb_dri2_get_buffers_cookie_t buffers_cookie;
1093    xcb_dri2_get_buffers_reply_t *buffers_reply;
1094    xcb_dri2_dri2_buffer_t *buffers;
1095    xcb_get_geometry_cookie_t geometry_cookie;
1096    xcb_get_geometry_reply_t *geometry_reply;
1097    xcb_generic_error_t *error;
1098    int stride, format;
1099 
1100    (void)ctx;
1101 
1102    drawable = (xcb_drawable_t)(uintptr_t)buffer;
1103    xcb_dri2_create_drawable(dri2_dpy->conn, drawable);
1104    attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
1105    buffers_cookie = xcb_dri2_get_buffers_unchecked(dri2_dpy->conn, drawable, 1,
1106                                                    1, attachments);
1107    geometry_cookie = xcb_get_geometry(dri2_dpy->conn, drawable);
1108    buffers_reply =
1109       xcb_dri2_get_buffers_reply(dri2_dpy->conn, buffers_cookie, NULL);
1110    if (buffers_reply == NULL)
1111       return NULL;
1112 
1113    buffers = xcb_dri2_get_buffers_buffers(buffers_reply);
1114    if (buffers == NULL) {
1115       free(buffers_reply);
1116       return NULL;
1117    }
1118 
1119    geometry_reply =
1120       xcb_get_geometry_reply(dri2_dpy->conn, geometry_cookie, &error);
1121    if (geometry_reply == NULL || error != NULL) {
1122       _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
1123       free(error);
1124       free(buffers_reply);
1125       free(geometry_reply);
1126       return NULL;
1127    }
1128 
1129    format = dri2_format_for_depth(dri2_dpy, geometry_reply->depth);
1130    if (format == __DRI_IMAGE_FORMAT_NONE) {
1131       _eglError(EGL_BAD_PARAMETER,
1132                 "dri2_create_image_khr: unsupported pixmap depth");
1133       free(buffers_reply);
1134       free(geometry_reply);
1135       return NULL;
1136    }
1137 
1138    dri2_img = malloc(sizeof *dri2_img);
1139    if (!dri2_img) {
1140       free(buffers_reply);
1141       free(geometry_reply);
1142       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1143       return EGL_NO_IMAGE_KHR;
1144    }
1145 
1146    _eglInitImage(&dri2_img->base, disp);
1147 
1148    stride = buffers[0].pitch / buffers[0].cpp;
1149    dri2_img->dri_image = dri2_dpy->image->createImageFromName(
1150       dri2_dpy->dri_screen_render_gpu, buffers_reply->width,
1151       buffers_reply->height, format, buffers[0].name, stride, dri2_img);
1152 
1153    free(buffers_reply);
1154    free(geometry_reply);
1155 
1156    return &dri2_img->base;
1157 }
1158 
1159 static _EGLImage *
dri2_x11_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)1160 dri2_x11_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
1161                           EGLClientBuffer buffer, const EGLint *attr_list)
1162 {
1163    switch (target) {
1164    case EGL_NATIVE_PIXMAP_KHR:
1165       return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
1166    default:
1167       return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
1168    }
1169 }
1170 
1171 static EGLBoolean
dri2_x11_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)1172 dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
1173                          EGLuint64KHR *ust, EGLuint64KHR *msc,
1174                          EGLuint64KHR *sbc)
1175 {
1176    struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
1177    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
1178    xcb_dri2_get_msc_cookie_t cookie;
1179    xcb_dri2_get_msc_reply_t *reply;
1180 
1181    cookie = xcb_dri2_get_msc(dri2_dpy->conn, dri2_surf->drawable);
1182    reply = xcb_dri2_get_msc_reply(dri2_dpy->conn, cookie, NULL);
1183 
1184    if (!reply)
1185       return _eglError(EGL_BAD_ACCESS, __func__);
1186 
1187    *ust = ((EGLuint64KHR)reply->ust_hi << 32) | reply->ust_lo;
1188    *msc = ((EGLuint64KHR)reply->msc_hi << 32) | reply->msc_lo;
1189    *sbc = ((EGLuint64KHR)reply->sbc_hi << 32) | reply->sbc_lo;
1190    free(reply);
1191 
1192    return EGL_TRUE;
1193 }
1194 
1195 static int
box_intersection_area(int16_t a_x,int16_t a_y,int16_t a_width,int16_t a_height,int16_t b_x,int16_t b_y,int16_t b_width,int16_t b_height)1196 box_intersection_area(int16_t a_x, int16_t a_y, int16_t a_width,
1197                       int16_t a_height, int16_t b_x, int16_t b_y,
1198                       int16_t b_width, int16_t b_height)
1199 {
1200    int w = MIN2(a_x + a_width, b_x + b_width) - MAX2(a_x, b_x);
1201    int h = MIN2(a_y + a_height, b_y + b_height) - MAX2(a_y, b_y);
1202 
1203    return (w < 0 || h < 0) ? 0 : w * h;
1204 }
1205 
1206 EGLBoolean
dri2_x11_get_msc_rate(_EGLDisplay * display,_EGLSurface * surface,EGLint * numerator,EGLint * denominator)1207 dri2_x11_get_msc_rate(_EGLDisplay *display, _EGLSurface *surface,
1208                       EGLint *numerator, EGLint *denominator)
1209 {
1210    struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
1211 
1212    loader_update_screen_resources(&dri2_dpy->screen_resources);
1213 
1214    if (dri2_dpy->screen_resources.num_crtcs == 0) {
1215       /* If there's no CRTC active, use the present fake vblank of 1Hz */
1216       *numerator = 1;
1217       *denominator = 1;
1218       return EGL_TRUE;
1219    }
1220 
1221    /* Default to the first CRTC in the list */
1222    *numerator = dri2_dpy->screen_resources.crtcs[0].refresh_numerator;
1223    *denominator = dri2_dpy->screen_resources.crtcs[0].refresh_denominator;
1224 
1225    /* If there's only one active CRTC, we're done */
1226    if (dri2_dpy->screen_resources.num_crtcs == 1)
1227       return EGL_TRUE;
1228 
1229    /* In a multi-monitor setup, look at each CRTC and perform a box
1230     * intersection between the CRTC and surface.  Use the CRTC whose
1231     * box intersection has the largest area.
1232     */
1233    if (surface->Type != EGL_WINDOW_BIT)
1234       return EGL_TRUE;
1235 
1236    xcb_window_t window = (uintptr_t)surface->NativeSurface;
1237 
1238    xcb_translate_coordinates_cookie_t cookie =
1239       xcb_translate_coordinates_unchecked(dri2_dpy->conn, window,
1240                                           dri2_dpy->screen->root, 0, 0);
1241    xcb_translate_coordinates_reply_t *reply =
1242       xcb_translate_coordinates_reply(dri2_dpy->conn, cookie, NULL);
1243 
1244    if (!reply) {
1245       _eglError(EGL_BAD_SURFACE,
1246                 "eglGetMscRateANGLE failed to translate coordinates");
1247       return EGL_FALSE;
1248    }
1249 
1250    int area = 0;
1251 
1252    for (unsigned c = 0; c < dri2_dpy->screen_resources.num_crtcs; c++) {
1253       struct loader_crtc_info *crtc = &dri2_dpy->screen_resources.crtcs[c];
1254 
1255       int c_area = box_intersection_area(
1256          reply->dst_x, reply->dst_y, surface->Width, surface->Height, crtc->x,
1257          crtc->y, crtc->width, crtc->height);
1258       if (c_area > area) {
1259          *numerator = crtc->refresh_numerator;
1260          *denominator = crtc->refresh_denominator;
1261          area = c_area;
1262       }
1263    }
1264 
1265    /* If the window is entirely off-screen, then area will still be 0.
1266     * We defaulted to the first CRTC in the list's refresh rate, earlier.
1267     */
1268 
1269    return EGL_TRUE;
1270 }
1271 
1272 static EGLBoolean
dri2_kopper_swap_interval(_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)1273 dri2_kopper_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
1274 {
1275    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1276    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1277 
1278    /* This can legitimately be null for lavapipe */
1279    if (dri2_dpy->kopper)
1280       dri2_dpy->kopper->setSwapInterval(dri2_surf->dri_drawable, interval);
1281 
1282    return EGL_TRUE;
1283 }
1284 
1285 static _EGLSurface *
dri2_kopper_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)1286 dri2_kopper_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
1287                                   void *native_window,
1288                                   const EGLint *attrib_list)
1289 {
1290    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1291    _EGLSurface *surf;
1292 
1293    surf = dri2_x11_create_surface(disp, EGL_WINDOW_BIT, conf, native_window,
1294                                   attrib_list);
1295    if (surf != NULL) {
1296       /* When we first create the DRI2 drawable, its swap interval on the
1297        * server side is 1.
1298        */
1299       surf->SwapInterval = 1;
1300 
1301       /* Override that with a driconf-set value. */
1302       dri2_kopper_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
1303    }
1304 
1305    return surf;
1306 }
1307 
1308 static EGLint
dri2_kopper_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)1309 dri2_kopper_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
1310 {
1311    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1312    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1313 
1314    /* This can legitimately be null for lavapipe */
1315    if (dri2_dpy->kopper)
1316       return dri2_dpy->kopper->queryBufferAge(dri2_surf->dri_drawable);
1317 
1318    return 0;
1319 }
1320 
1321 static EGLint
dri2_swrast_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)1322 dri2_swrast_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
1323 {
1324    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1325    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1326 
1327    assert(dri2_dpy->swrast);
1328    return dri2_dpy->swrast->queryBufferAge(dri2_surf->dri_drawable);
1329 }
1330 
1331 static const struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
1332    .authenticate = NULL,
1333    .create_window_surface = dri2_x11_create_window_surface,
1334    .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1335    .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1336    .destroy_surface = dri2_x11_destroy_surface,
1337    .create_image = dri2_create_image_khr,
1338    .swap_buffers = dri2_x11_swap_buffers,
1339    .swap_buffers_region = dri2_x11_swap_buffers_region,
1340    .post_sub_buffer = dri2_x11_post_sub_buffer,
1341    .copy_buffers = dri2_x11_copy_buffers,
1342    .query_buffer_age = dri2_swrast_query_buffer_age,
1343    /* XXX: should really implement this since X11 has pixmaps */
1344    .query_surface = dri2_query_surface,
1345    .get_msc_rate = dri2_x11_get_msc_rate,
1346    .get_dri_drawable = dri2_surface_get_dri_drawable,
1347 };
1348 
1349 static const struct dri2_egl_display_vtbl dri2_x11_kopper_display_vtbl = {
1350    .authenticate = NULL,
1351    .create_window_surface = dri2_kopper_create_window_surface,
1352    .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1353    .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1354    .destroy_surface = dri2_x11_destroy_surface,
1355    .create_image = dri2_create_image_khr,
1356    .swap_interval = dri2_kopper_swap_interval,
1357    .swap_buffers = dri2_x11_swap_buffers,
1358    .swap_buffers_region = dri2_x11_swap_buffers_region,
1359    .post_sub_buffer = dri2_x11_post_sub_buffer,
1360    .copy_buffers = dri2_x11_copy_buffers,
1361    .query_buffer_age = dri2_kopper_query_buffer_age,
1362    /* XXX: should really implement this since X11 has pixmaps */
1363    .query_surface = dri2_query_surface,
1364    .get_msc_rate = dri2_x11_get_msc_rate,
1365    .get_dri_drawable = dri2_surface_get_dri_drawable,
1366 };
1367 
1368 static const struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
1369    .authenticate = dri2_x11_authenticate,
1370    .create_window_surface = dri2_x11_create_window_surface,
1371    .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1372    .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1373    .destroy_surface = dri2_x11_destroy_surface,
1374    .create_image = dri2_x11_create_image_khr,
1375    .swap_interval = dri2_x11_swap_interval,
1376    .swap_buffers = dri2_x11_swap_buffers,
1377    .swap_buffers_region = dri2_x11_swap_buffers_region,
1378    .post_sub_buffer = dri2_x11_post_sub_buffer,
1379    .copy_buffers = dri2_x11_copy_buffers,
1380    .query_surface = dri2_query_surface,
1381    .get_sync_values = dri2_x11_get_sync_values,
1382    .get_msc_rate = dri2_x11_get_msc_rate,
1383    .get_dri_drawable = dri2_surface_get_dri_drawable,
1384 };
1385 
1386 static const __DRIswrastLoaderExtension swrast_loader_extension = {
1387    .base = {__DRI_SWRAST_LOADER, 1},
1388 
1389    .getDrawableInfo = swrastGetDrawableInfo,
1390    .putImage = swrastPutImage,
1391    .getImage = swrastGetImage,
1392 };
1393 
1394 static_assert(sizeof(struct kopper_vk_surface_create_storage) >=
1395                  sizeof(VkXcbSurfaceCreateInfoKHR),
1396               "");
1397 
1398 static void
kopperSetSurfaceCreateInfo(void * _draw,struct kopper_loader_info * ci)1399 kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *ci)
1400 {
1401    struct dri2_egl_surface *dri2_surf = _draw;
1402    struct dri2_egl_display *dri2_dpy =
1403       dri2_egl_display(dri2_surf->base.Resource.Display);
1404    VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&ci->bos;
1405 
1406    if (dri2_surf->base.Type != EGL_WINDOW_BIT)
1407       return;
1408    xcb->sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
1409    xcb->pNext = NULL;
1410    xcb->flags = 0;
1411    xcb->connection = dri2_dpy->conn;
1412    xcb->window = dri2_surf->drawable;
1413    ci->has_alpha = dri2_surf->depth == 32;
1414 }
1415 
1416 static const __DRIkopperLoaderExtension kopper_loader_extension = {
1417    .base = {__DRI_KOPPER_LOADER, 1},
1418 
1419    .SetSurfaceCreateInfo = kopperSetSurfaceCreateInfo,
1420 };
1421 
1422 static const __DRIextension *swrast_loader_extensions[] = {
1423    &swrast_loader_extension.base,
1424    &image_lookup_extension.base,
1425    &kopper_loader_extension.base,
1426    NULL,
1427 };
1428 
1429 static int
dri2_find_screen_for_display(const _EGLDisplay * disp,int fallback_screen)1430 dri2_find_screen_for_display(const _EGLDisplay *disp, int fallback_screen)
1431 {
1432    const EGLAttrib *attr;
1433 
1434    if (!disp->Options.Attribs)
1435       return fallback_screen;
1436 
1437    for (attr = disp->Options.Attribs; attr[0] != EGL_NONE; attr += 2) {
1438       if (attr[0] == EGL_PLATFORM_X11_SCREEN_EXT ||
1439           attr[0] == EGL_PLATFORM_XCB_SCREEN_EXT)
1440          return attr[1];
1441    }
1442 
1443    return fallback_screen;
1444 }
1445 
1446 static EGLBoolean
dri2_get_xcb_connection(_EGLDisplay * disp,struct dri2_egl_display * dri2_dpy)1447 dri2_get_xcb_connection(_EGLDisplay *disp, struct dri2_egl_display *dri2_dpy)
1448 {
1449    xcb_screen_iterator_t s;
1450    int screen;
1451    const char *msg;
1452 
1453    disp->DriverData = (void *)dri2_dpy;
1454    if (disp->PlatformDisplay == NULL) {
1455       dri2_dpy->conn = xcb_connect(NULL, &screen);
1456       dri2_dpy->own_device = true;
1457       screen = dri2_find_screen_for_display(disp, screen);
1458    } else if (disp->Platform == _EGL_PLATFORM_X11) {
1459       Display *dpy = disp->PlatformDisplay;
1460       dri2_dpy->conn = XGetXCBConnection(dpy);
1461       screen = DefaultScreen(dpy);
1462    } else {
1463       /*   _EGL_PLATFORM_XCB   */
1464       dri2_dpy->conn = disp->PlatformDisplay;
1465       screen = dri2_find_screen_for_display(disp, 0);
1466    }
1467 
1468    if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) {
1469       msg = "xcb_connect failed";
1470       goto disconnect;
1471    }
1472 
1473    s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
1474    dri2_dpy->screen = get_xcb_screen(s, screen);
1475    if (!dri2_dpy->screen) {
1476       msg = "failed to get xcb screen";
1477       goto disconnect;
1478    }
1479 
1480    return EGL_TRUE;
1481 disconnect:
1482    if (disp->PlatformDisplay == NULL)
1483       xcb_disconnect(dri2_dpy->conn);
1484 
1485    return _eglError(EGL_BAD_ALLOC, msg);
1486 }
1487 
1488 static void
dri2_x11_setup_swap_interval(_EGLDisplay * disp)1489 dri2_x11_setup_swap_interval(_EGLDisplay *disp)
1490 {
1491    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1492    int arbitrary_max_interval = 1000;
1493 
1494    /* default behavior for no SwapBuffers support: no vblank syncing
1495     * either.
1496     */
1497    dri2_dpy->min_swap_interval = 0;
1498    dri2_dpy->max_swap_interval = 0;
1499    dri2_dpy->default_swap_interval = 0;
1500 
1501    if (!dri2_dpy->swap_available)
1502       return;
1503 
1504    /* If we do have swapbuffers, then we can support pretty much any swap
1505     * interval. Unless we're kopper, for now.
1506     */
1507    if (dri2_dpy->kopper)
1508       arbitrary_max_interval = 1;
1509 
1510    dri2_setup_swap_interval(disp, arbitrary_max_interval);
1511 }
1512 
1513 static EGLBoolean
dri2_initialize_x11_swrast(_EGLDisplay * disp)1514 dri2_initialize_x11_swrast(_EGLDisplay *disp)
1515 {
1516    struct dri2_egl_display *dri2_dpy = dri2_display_create();
1517    if (!dri2_dpy)
1518       return EGL_FALSE;
1519 
1520    if (!dri2_get_xcb_connection(disp, dri2_dpy))
1521       goto cleanup;
1522 
1523    /*
1524     * Every hardware driver_name is set using strdup. Doing the same in
1525     * here will allow is to simply free the memory at dri2_terminate().
1526     */
1527    dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast");
1528    if (disp->Options.Zink &&
1529        !debug_get_bool_option("LIBGL_DRI3_DISABLE", false))
1530       dri3_x11_connect(dri2_dpy);
1531    if (!dri2_load_driver_swrast(disp))
1532       goto cleanup;
1533 
1534    dri2_dpy->loader_extensions = swrast_loader_extensions;
1535 
1536    if (!dri2_create_screen(disp))
1537       goto cleanup;
1538 
1539    if (!dri2_setup_extensions(disp))
1540       goto cleanup;
1541 
1542    if (!dri2_setup_device(disp, true)) {
1543       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to setup EGLDevice");
1544       goto cleanup;
1545    }
1546 
1547    dri2_setup_screen(disp);
1548 
1549    if (disp->Options.Zink) {
1550       /* kopper */
1551 #ifdef HAVE_WAYLAND_PLATFORM
1552       dri2_dpy->device_name = strdup("zink");
1553 #endif
1554       dri2_dpy->swap_available = EGL_TRUE;
1555       dri2_x11_setup_swap_interval(disp);
1556       if (dri2_dpy->fd_render_gpu == dri2_dpy->fd_display_gpu)
1557          disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1558       disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1559       disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1560       disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1561 
1562       if (dri2_dpy->multibuffers_available)
1563          dri2_set_WL_bind_wayland_display(disp);
1564    }
1565    disp->Extensions.EXT_buffer_age = EGL_TRUE;
1566    disp->Extensions.ANGLE_sync_control_rate = EGL_TRUE;
1567 
1568    dri2_x11_add_configs_for_visuals(dri2_dpy, disp, !disp->Options.Zink);
1569 
1570    /* Fill vtbl last to prevent accidentally calling virtual function during
1571     * initialization.
1572     */
1573    if (disp->Options.Zink)
1574       dri2_dpy->vtbl = &dri2_x11_kopper_display_vtbl;
1575    else
1576       dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;
1577 
1578    return EGL_TRUE;
1579 
1580 cleanup:
1581    dri2_display_destroy(disp);
1582    return EGL_FALSE;
1583 }
1584 
1585 #ifdef HAVE_DRI3
1586 
1587 static const __DRIextension *dri3_image_loader_extensions[] = {
1588    &dri3_image_loader_extension.base,
1589    &image_lookup_extension.base,
1590    &use_invalidate.base,
1591    &background_callable_extension.base,
1592    NULL,
1593 };
1594 
1595 static enum dri2_egl_driver_fail
dri2_initialize_x11_dri3(_EGLDisplay * disp)1596 dri2_initialize_x11_dri3(_EGLDisplay *disp)
1597 {
1598    struct dri2_egl_display *dri2_dpy = dri2_display_create();
1599    enum dri2_egl_driver_fail status = DRI2_EGL_DRIVER_FAILED;
1600    if (!dri2_dpy)
1601       return DRI2_EGL_DRIVER_FAILED;
1602 
1603    if (!dri2_get_xcb_connection(disp, dri2_dpy))
1604       goto cleanup;
1605 
1606    status = dri3_x11_connect(dri2_dpy);
1607    if (status != DRI2_EGL_DRIVER_LOADED)
1608       goto cleanup;
1609 
1610    if (!dri2_load_driver_dri3(disp))
1611       goto cleanup;
1612 
1613    dri2_dpy->loader_extensions = dri3_image_loader_extensions;
1614 
1615    dri2_dpy->swap_available = true;
1616    dri2_dpy->invalidate_available = true;
1617 
1618    if (!dri2_create_screen(disp))
1619       goto cleanup;
1620 
1621    if (!dri2_setup_extensions(disp))
1622       goto cleanup;
1623 
1624    if (!dri2_setup_device(disp, false)) {
1625       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to setup EGLDevice");
1626       goto cleanup;
1627    }
1628 
1629    dri2_setup_screen(disp);
1630 
1631    dri2_x11_setup_swap_interval(disp);
1632 
1633    if (dri2_dpy->fd_render_gpu == dri2_dpy->fd_display_gpu)
1634       disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1635    disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1636    disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1637    disp->Extensions.ANGLE_sync_control_rate = EGL_TRUE;
1638    disp->Extensions.EXT_buffer_age = EGL_TRUE;
1639    disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1640 
1641    dri2_set_WL_bind_wayland_display(disp);
1642 
1643    dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false);
1644 
1645    loader_init_screen_resources(&dri2_dpy->screen_resources, dri2_dpy->conn,
1646                                 dri2_dpy->screen);
1647 
1648    dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
1649    dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
1650    dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
1651    dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;
1652    dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;
1653    dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;
1654 
1655    /* Fill vtbl last to prevent accidentally calling virtual function during
1656     * initialization.
1657     */
1658    dri2_dpy->vtbl = &dri3_x11_display_vtbl;
1659 
1660    _eglLog(_EGL_INFO, "Using DRI3");
1661 
1662    return DRI2_EGL_DRIVER_LOADED;
1663 
1664 cleanup:
1665    dri2_display_destroy(disp);
1666    return status;
1667 }
1668 #endif
1669 
1670 static const __DRIdri2LoaderExtension dri2_loader_extension_old = {
1671    .base = {__DRI_DRI2_LOADER, 2},
1672 
1673    .getBuffers = dri2_x11_get_buffers,
1674    .flushFrontBuffer = dri2_x11_flush_front_buffer,
1675    .getBuffersWithFormat = NULL,
1676 };
1677 
1678 static const __DRIdri2LoaderExtension dri2_loader_extension = {
1679    .base = {__DRI_DRI2_LOADER, 3},
1680 
1681    .getBuffers = dri2_x11_get_buffers,
1682    .flushFrontBuffer = dri2_x11_flush_front_buffer,
1683    .getBuffersWithFormat = dri2_x11_get_buffers_with_format,
1684 };
1685 
1686 static const __DRIextension *dri2_loader_extensions_old[] = {
1687    &dri2_loader_extension_old.base,
1688    &image_lookup_extension.base,
1689    &background_callable_extension.base,
1690    NULL,
1691 };
1692 
1693 static const __DRIextension *dri2_loader_extensions[] = {
1694    &dri2_loader_extension.base,
1695    &image_lookup_extension.base,
1696    &use_invalidate.base,
1697    &background_callable_extension.base,
1698    NULL,
1699 };
1700 
1701 static EGLBoolean
dri2_initialize_x11_dri2(_EGLDisplay * disp)1702 dri2_initialize_x11_dri2(_EGLDisplay *disp)
1703 {
1704    struct dri2_egl_display *dri2_dpy = dri2_display_create();
1705    if (!dri2_dpy)
1706       return EGL_FALSE;
1707 
1708    if (!dri2_get_xcb_connection(disp, dri2_dpy))
1709       goto cleanup;
1710 
1711    if (!dri2_x11_connect(dri2_dpy))
1712       goto cleanup;
1713 
1714    if (!dri2_load_driver(disp))
1715       goto cleanup;
1716 
1717    if (dri2_dpy->dri2_minor >= 1)
1718       dri2_dpy->loader_extensions = dri2_loader_extensions;
1719    else
1720       dri2_dpy->loader_extensions = dri2_loader_extensions_old;
1721 
1722    dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
1723    dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
1724 
1725    if (!dri2_create_screen(disp))
1726       goto cleanup;
1727 
1728    if (!dri2_setup_extensions(disp))
1729       goto cleanup;
1730 
1731    if (!dri2_setup_device(disp, false)) {
1732       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to setup EGLDevice");
1733       goto cleanup;
1734    }
1735 
1736    dri2_setup_screen(disp);
1737 
1738    dri2_x11_setup_swap_interval(disp);
1739 
1740    disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1741    disp->Extensions.NOK_swap_region = EGL_TRUE;
1742    disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1743    disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
1744    disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1745    disp->Extensions.ANGLE_sync_control_rate = EGL_TRUE;
1746 
1747    dri2_set_WL_bind_wayland_display(disp);
1748 
1749    dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true);
1750 
1751    /* Fill vtbl last to prevent accidentally calling virtual function during
1752     * initialization.
1753     */
1754    dri2_dpy->vtbl = &dri2_x11_display_vtbl;
1755 
1756    _eglLog(_EGL_INFO, "Using DRI2");
1757 
1758    return EGL_TRUE;
1759 
1760 cleanup:
1761    dri2_display_destroy(disp);
1762    return EGL_FALSE;
1763 }
1764 
1765 EGLBoolean
dri2_initialize_x11(_EGLDisplay * disp)1766 dri2_initialize_x11(_EGLDisplay *disp)
1767 {
1768    enum dri2_egl_driver_fail status = DRI2_EGL_DRIVER_FAILED;
1769    if (disp->Options.ForceSoftware || disp->Options.Zink)
1770       return dri2_initialize_x11_swrast(disp);
1771 
1772 #ifdef HAVE_DRI3
1773    if (!debug_get_bool_option("LIBGL_DRI3_DISABLE", false)) {
1774       status = dri2_initialize_x11_dri3(disp);
1775       if (status == DRI2_EGL_DRIVER_LOADED)
1776          return EGL_TRUE;
1777    }
1778 #endif
1779 
1780    if (!debug_get_bool_option("LIBGL_DRI2_DISABLE", false) &&
1781        status != DRI2_EGL_DRIVER_PREFER_ZINK)
1782       if (dri2_initialize_x11_dri2(disp))
1783          return EGL_TRUE;
1784 
1785    return EGL_FALSE;
1786 }
1787 
1788 void
dri2_teardown_x11(struct dri2_egl_display * dri2_dpy)1789 dri2_teardown_x11(struct dri2_egl_display *dri2_dpy)
1790 {
1791    if (dri2_dpy->dri2_major >= 3)
1792       loader_destroy_screen_resources(&dri2_dpy->screen_resources);
1793 
1794    if (dri2_dpy->own_device)
1795       xcb_disconnect(dri2_dpy->conn);
1796 }
1797