• 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 <stdbool.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <limits.h>
34 #include <dlfcn.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #ifdef HAVE_LIBDRM
39 #include <xf86drm.h>
40 #endif
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 
44 #include "egl_dri2.h"
45 #include "egl_dri2_fallbacks.h"
46 #include "loader.h"
47 
48 #ifdef HAVE_DRI3
49 #include "platform_x11_dri3.h"
50 #endif
51 
52 static EGLBoolean
53 dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
54                        EGLint interval);
55 
56 static void
swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,struct dri2_egl_surface * dri2_surf)57 swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
58                      struct dri2_egl_surface * dri2_surf)
59 {
60    uint32_t           mask;
61    const uint32_t     function = GXcopy;
62    uint32_t           valgc[2];
63 
64    /* create GC's */
65    dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
66    mask = XCB_GC_FUNCTION;
67    xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
68 
69    dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
70    mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
71    valgc[0] = function;
72    valgc[1] = False;
73    xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
74    switch (dri2_surf->depth) {
75       case 32:
76       case 24:
77          dri2_surf->bytes_per_pixel = 4;
78          break;
79       case 16:
80          dri2_surf->bytes_per_pixel = 2;
81          break;
82       case 8:
83          dri2_surf->bytes_per_pixel = 1;
84          break;
85       case 0:
86          dri2_surf->bytes_per_pixel = 0;
87          break;
88       default:
89          _eglLog(_EGL_WARNING, "unsupported depth %d", dri2_surf->depth);
90    }
91 }
92 
93 static void
swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,struct dri2_egl_surface * dri2_surf)94 swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
95                       struct dri2_egl_surface * dri2_surf)
96 {
97    xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
98    xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
99 }
100 
101 static void
swrastGetDrawableInfo(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)102 swrastGetDrawableInfo(__DRIdrawable * draw,
103                       int *x, int *y, int *w, int *h,
104                       void *loaderPrivate)
105 {
106    struct dri2_egl_surface *dri2_surf = loaderPrivate;
107    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
108 
109    xcb_get_geometry_cookie_t cookie;
110    xcb_get_geometry_reply_t *reply;
111    xcb_generic_error_t *error;
112 
113    *w = *h = 0;
114    cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
115    reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
116    if (reply == NULL)
117       return;
118 
119    if (error != NULL) {
120       _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
121       free(error);
122    } else {
123       *w = reply->width;
124       *h = reply->height;
125    }
126    free(reply);
127 }
128 
129 static void
swrastPutImage(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)130 swrastPutImage(__DRIdrawable * draw, int op,
131                int x, int y, int w, int h,
132                char *data, void *loaderPrivate)
133 {
134    struct dri2_egl_surface *dri2_surf = loaderPrivate;
135    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
136 
137    xcb_gcontext_t gc;
138 
139    switch (op) {
140    case __DRI_SWRAST_IMAGE_OP_DRAW:
141       gc = dri2_surf->gc;
142       break;
143    case __DRI_SWRAST_IMAGE_OP_SWAP:
144       gc = dri2_surf->swapgc;
145       break;
146    default:
147       return;
148    }
149 
150    xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
151                  gc, w, h, x, y, 0, dri2_surf->depth,
152                  w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
153 }
154 
155 static void
swrastGetImage(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)156 swrastGetImage(__DRIdrawable * read,
157                int x, int y, int w, int h,
158                char *data, void *loaderPrivate)
159 {
160    struct dri2_egl_surface *dri2_surf = loaderPrivate;
161    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
162 
163    xcb_get_image_cookie_t cookie;
164    xcb_get_image_reply_t *reply;
165    xcb_generic_error_t *error;
166 
167    cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
168                            dri2_surf->drawable, x, y, w, h, ~0);
169    reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
170    if (reply == NULL)
171       return;
172 
173    if (error != NULL) {
174       _eglLog(_EGL_WARNING, "error in xcb_get_image");
175       free(error);
176    } else {
177       uint32_t bytes = xcb_get_image_data_length(reply);
178       uint8_t *idata = xcb_get_image_data(reply);
179       memcpy(data, idata, bytes);
180    }
181    free(reply);
182 }
183 
184 
185 static xcb_screen_t *
get_xcb_screen(xcb_screen_iterator_t iter,int screen)186 get_xcb_screen(xcb_screen_iterator_t iter, int screen)
187 {
188     for (; iter.rem; --screen, xcb_screen_next(&iter))
189         if (screen == 0)
190             return iter.data;
191 
192     return NULL;
193 }
194 
195 
196 /**
197  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
198  */
199 static _EGLSurface *
dri2_x11_create_surface(_EGLDriver * drv,_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)200 dri2_x11_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
201                         _EGLConfig *conf, void *native_surface,
202                         const EGLint *attrib_list)
203 {
204    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
205    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
206    struct dri2_egl_surface *dri2_surf;
207    xcb_get_geometry_cookie_t cookie;
208    xcb_get_geometry_reply_t *reply;
209    xcb_generic_error_t *error;
210    xcb_drawable_t drawable;
211    const __DRIconfig *config;
212 
213    STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
214    drawable = (uintptr_t) native_surface;
215 
216    (void) drv;
217 
218    dri2_surf = malloc(sizeof *dri2_surf);
219    if (!dri2_surf) {
220       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
221       return NULL;
222    }
223 
224    if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
225       goto cleanup_surf;
226 
227    dri2_surf->region = XCB_NONE;
228    if (type == EGL_PBUFFER_BIT) {
229       dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
230       xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
231                        dri2_surf->drawable, dri2_dpy->screen->root,
232 			dri2_surf->base.Width, dri2_surf->base.Height);
233    } else {
234       if (!drawable) {
235          if (type == EGL_WINDOW_BIT)
236             _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
237          else
238             _eglError(EGL_BAD_NATIVE_PIXMAP, "dri2_create_surface");
239          goto cleanup_surf;
240       }
241       dri2_surf->drawable = drawable;
242    }
243 
244    config = dri2_get_dri_config(dri2_conf, type,
245                                 dri2_surf->base.GLColorspace);
246 
247    if (dri2_dpy->dri2) {
248       dri2_surf->dri_drawable =
249          dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen, config,
250                                            dri2_surf);
251    } else {
252       assert(dri2_dpy->swrast);
253       dri2_surf->dri_drawable =
254          dri2_dpy->swrast->createNewDrawable(dri2_dpy->dri_screen, config,
255                                              dri2_surf);
256    }
257 
258    if (dri2_surf->dri_drawable == NULL) {
259       _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
260       goto cleanup_pixmap;
261    }
262 
263    if (type != EGL_PBUFFER_BIT) {
264       cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
265       reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
266       if (error != NULL) {
267          if (error->error_code == BadAlloc)
268             _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
269          else if (type == EGL_WINDOW_BIT)
270             _eglError(EGL_BAD_NATIVE_WINDOW, "xcb_get_geometry");
271          else
272             _eglError(EGL_BAD_NATIVE_PIXMAP, "xcb_get_geometry");
273          free(error);
274          goto cleanup_dri_drawable;
275       } else if (reply == NULL) {
276          _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
277          goto cleanup_dri_drawable;
278       }
279 
280       dri2_surf->base.Width = reply->width;
281       dri2_surf->base.Height = reply->height;
282       dri2_surf->depth = reply->depth;
283       free(reply);
284    }
285 
286    if (dri2_dpy->dri2) {
287       xcb_void_cookie_t cookie;
288       int conn_error;
289 
290       cookie = xcb_dri2_create_drawable_checked(dri2_dpy->conn,
291                                                 dri2_surf->drawable);
292       error = xcb_request_check(dri2_dpy->conn, cookie);
293       conn_error = xcb_connection_has_error(dri2_dpy->conn);
294       if (conn_error || error != NULL) {
295          if (type == EGL_PBUFFER_BIT || conn_error || error->error_code == BadAlloc)
296             _eglError(EGL_BAD_ALLOC, "xcb_dri2_create_drawable_checked");
297          else if (type == EGL_WINDOW_BIT)
298             _eglError(EGL_BAD_NATIVE_WINDOW,
299                       "xcb_dri2_create_drawable_checked");
300          else
301             _eglError(EGL_BAD_NATIVE_PIXMAP,
302                       "xcb_dri2_create_drawable_checked");
303          free(error);
304          goto cleanup_dri_drawable;
305       }
306    } else {
307       if (type == EGL_PBUFFER_BIT) {
308          dri2_surf->depth = _eglGetConfigKey(conf, EGL_BUFFER_SIZE);
309       }
310       swrastCreateDrawable(dri2_dpy, dri2_surf);
311    }
312 
313    /* we always copy the back buffer to front */
314    dri2_surf->base.PostSubBufferSupportedNV = EGL_TRUE;
315 
316    return &dri2_surf->base;
317 
318  cleanup_dri_drawable:
319    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
320  cleanup_pixmap:
321    if (type == EGL_PBUFFER_BIT)
322       xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
323  cleanup_surf:
324    free(dri2_surf);
325 
326    return NULL;
327 }
328 
329 /**
330  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
331  */
332 static _EGLSurface *
dri2_x11_create_window_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)333 dri2_x11_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
334                                _EGLConfig *conf, void *native_window,
335                                const EGLint *attrib_list)
336 {
337    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
338    _EGLSurface *surf;
339 
340    surf = dri2_x11_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
341                                   native_window, attrib_list);
342    if (surf != NULL) {
343       /* When we first create the DRI2 drawable, its swap interval on the
344        * server side is 1.
345        */
346       surf->SwapInterval = 1;
347 
348       /* Override that with a driconf-set value. */
349       dri2_x11_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
350    }
351 
352    return surf;
353 }
354 
355 static _EGLSurface *
dri2_x11_create_pixmap_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)356 dri2_x11_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
357                                _EGLConfig *conf, void *native_pixmap,
358                                const EGLint *attrib_list)
359 {
360    return dri2_x11_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
361                                   native_pixmap, attrib_list);
362 }
363 
364 static _EGLSurface *
dri2_x11_create_pbuffer_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)365 dri2_x11_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
366                                 _EGLConfig *conf, const EGLint *attrib_list)
367 {
368    return dri2_x11_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
369                                   XCB_WINDOW_NONE, attrib_list);
370 }
371 
372 static EGLBoolean
dri2_x11_destroy_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf)373 dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
374 {
375    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
376    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
377 
378    (void) drv;
379 
380    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
381 
382    if (dri2_dpy->dri2) {
383       xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
384    } else {
385       assert(dri2_dpy->swrast);
386       swrastDestroyDrawable(dri2_dpy, dri2_surf);
387    }
388 
389    if (surf->Type == EGL_PBUFFER_BIT)
390       xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
391 
392    free(surf);
393 
394    return EGL_TRUE;
395 }
396 
397 /**
398  * Function utilizes swrastGetDrawableInfo to get surface
399  * geometry from x server and calls default query surface
400  * implementation that returns the updated values.
401  *
402  * In case of errors we still return values that we currently
403  * have.
404  */
405 static EGLBoolean
dri2_query_surface(_EGLDriver * drv,_EGLDisplay * dpy,_EGLSurface * surf,EGLint attribute,EGLint * value)406 dri2_query_surface(_EGLDriver *drv, _EGLDisplay *dpy,
407                    _EGLSurface *surf, EGLint attribute,
408                    EGLint *value)
409 {
410    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
411    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
412    int x, y, w = -1, h = -1;
413 
414    __DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
415 
416    switch (attribute) {
417    case EGL_WIDTH:
418    case EGL_HEIGHT:
419       swrastGetDrawableInfo(drawable, &x, &y, &w, &h, dri2_surf);
420       if (w != -1 && h != -1) {
421          surf->Width = w;
422          surf->Height = h;
423       }
424       break;
425    default:
426       break;
427    }
428    return _eglQuerySurface(drv, dpy, surf, attribute, value);
429 }
430 
431 /**
432  * Process list of buffer received from the server
433  *
434  * Processes the list of buffers received in a reply from the server to either
435  * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
436  */
437 static void
dri2_x11_process_buffers(struct dri2_egl_surface * dri2_surf,xcb_dri2_dri2_buffer_t * buffers,unsigned count)438 dri2_x11_process_buffers(struct dri2_egl_surface *dri2_surf,
439                          xcb_dri2_dri2_buffer_t *buffers, unsigned count)
440 {
441    struct dri2_egl_display *dri2_dpy =
442       dri2_egl_display(dri2_surf->base.Resource.Display);
443    xcb_rectangle_t rectangle;
444    unsigned i;
445 
446    dri2_surf->buffer_count = count;
447    dri2_surf->have_fake_front = 0;
448 
449    /* This assumes the DRI2 buffer attachment tokens matches the
450     * __DRIbuffer tokens. */
451    for (i = 0; i < count; i++) {
452       dri2_surf->buffers[i].attachment = buffers[i].attachment;
453       dri2_surf->buffers[i].name = buffers[i].name;
454       dri2_surf->buffers[i].pitch = buffers[i].pitch;
455       dri2_surf->buffers[i].cpp = buffers[i].cpp;
456       dri2_surf->buffers[i].flags = buffers[i].flags;
457 
458       /* We only use the DRI drivers single buffer configs.  This
459        * means that if we try to render to a window, DRI2 will give us
460        * the fake front buffer, which we'll use as a back buffer.
461        * Note that EGL doesn't require that several clients rendering
462        * to the same window must see the same aux buffers. */
463       if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
464          dri2_surf->have_fake_front = 1;
465    }
466 
467    if (dri2_surf->region != XCB_NONE)
468       xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
469 
470    rectangle.x = 0;
471    rectangle.y = 0;
472    rectangle.width = dri2_surf->base.Width;
473    rectangle.height = dri2_surf->base.Height;
474    dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
475    xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
476 }
477 
478 static __DRIbuffer *
dri2_x11_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)479 dri2_x11_get_buffers(__DRIdrawable * driDrawable,
480                      int *width, int *height,
481                      unsigned int *attachments, int count,
482                      int *out_count, void *loaderPrivate)
483 {
484    struct dri2_egl_surface *dri2_surf = loaderPrivate;
485    struct dri2_egl_display *dri2_dpy =
486       dri2_egl_display(dri2_surf->base.Resource.Display);
487    xcb_dri2_dri2_buffer_t *buffers;
488    xcb_dri2_get_buffers_reply_t *reply;
489    xcb_dri2_get_buffers_cookie_t cookie;
490 
491    (void) driDrawable;
492 
493    cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
494 					    dri2_surf->drawable,
495 					    count, count, attachments);
496    reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
497    if (reply == NULL)
498       return NULL;
499    buffers = xcb_dri2_get_buffers_buffers (reply);
500    if (buffers == NULL)
501       return NULL;
502 
503    *out_count = reply->count;
504    dri2_surf->base.Width = *width = reply->width;
505    dri2_surf->base.Height = *height = reply->height;
506    dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
507 
508    free(reply);
509 
510    return dri2_surf->buffers;
511 }
512 
513 static __DRIbuffer *
dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)514 dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,
515                                  int *width, int *height,
516                                  unsigned int *attachments, int count,
517                                  int *out_count, void *loaderPrivate)
518 {
519    struct dri2_egl_surface *dri2_surf = loaderPrivate;
520    struct dri2_egl_display *dri2_dpy =
521       dri2_egl_display(dri2_surf->base.Resource.Display);
522    xcb_dri2_dri2_buffer_t *buffers;
523    xcb_dri2_get_buffers_with_format_reply_t *reply;
524    xcb_dri2_get_buffers_with_format_cookie_t cookie;
525    xcb_dri2_attach_format_t *format_attachments;
526 
527    (void) driDrawable;
528 
529    format_attachments = (xcb_dri2_attach_format_t *) attachments;
530    cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
531 							dri2_surf->drawable,
532 							count, count,
533 							format_attachments);
534 
535    reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
536 						   cookie, NULL);
537    if (reply == NULL)
538       return NULL;
539 
540    buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
541    dri2_surf->base.Width = *width = reply->width;
542    dri2_surf->base.Height = *height = reply->height;
543    *out_count = reply->count;
544    dri2_x11_process_buffers(dri2_surf, buffers, *out_count);
545 
546    free(reply);
547 
548    return dri2_surf->buffers;
549 }
550 
551 static void
dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)552 dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
553 {
554    (void) driDrawable;
555 
556    /* FIXME: Does EGL support front buffer rendering at all? */
557 
558 #if 0
559    struct dri2_egl_surface *dri2_surf = loaderPrivate;
560 
561    dri2WaitGL(dri2_surf);
562 #else
563    (void) loaderPrivate;
564 #endif
565 }
566 
567 static int
dri2_x11_do_authenticate(struct dri2_egl_display * dri2_dpy,uint32_t id)568 dri2_x11_do_authenticate(struct dri2_egl_display *dri2_dpy, uint32_t id)
569 {
570    xcb_dri2_authenticate_reply_t *authenticate;
571    xcb_dri2_authenticate_cookie_t authenticate_cookie;
572    int ret = 0;
573 
574    authenticate_cookie =
575       xcb_dri2_authenticate_unchecked(dri2_dpy->conn, dri2_dpy->screen->root, id);
576    authenticate =
577       xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
578 
579    if (authenticate == NULL || !authenticate->authenticated)
580       ret = -1;
581 
582    free(authenticate);
583 
584    return ret;
585 }
586 
587 static EGLBoolean
dri2_x11_local_authenticate(struct dri2_egl_display * dri2_dpy)588 dri2_x11_local_authenticate(struct dri2_egl_display *dri2_dpy)
589 {
590 #ifdef HAVE_LIBDRM
591    drm_magic_t magic;
592 
593    if (drmGetMagic(dri2_dpy->fd, &magic)) {
594       _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
595       return EGL_FALSE;
596    }
597 
598    if (dri2_x11_do_authenticate(dri2_dpy, magic) < 0) {
599       _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
600       return EGL_FALSE;
601    }
602 #endif
603    return EGL_TRUE;
604 }
605 
606 static EGLBoolean
dri2_x11_connect(struct dri2_egl_display * dri2_dpy)607 dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
608 {
609    xcb_xfixes_query_version_reply_t *xfixes_query;
610    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
611    xcb_dri2_query_version_reply_t *dri2_query;
612    xcb_dri2_query_version_cookie_t dri2_query_cookie;
613    xcb_dri2_connect_reply_t *connect;
614    xcb_dri2_connect_cookie_t connect_cookie;
615    xcb_generic_error_t *error;
616    char *driver_name, *loader_driver_name, *device_name;
617    const xcb_query_extension_reply_t *extension;
618 
619    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
620    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
621 
622    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
623    if (!(extension && extension->present))
624       return EGL_FALSE;
625 
626    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri2_id);
627    if (!(extension && extension->present))
628       return EGL_FALSE;
629 
630    xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
631 						  XCB_XFIXES_MAJOR_VERSION,
632 						  XCB_XFIXES_MINOR_VERSION);
633 
634    dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
635 					       XCB_DRI2_MAJOR_VERSION,
636 					       XCB_DRI2_MINOR_VERSION);
637 
638    connect_cookie = xcb_dri2_connect_unchecked(dri2_dpy->conn, dri2_dpy->screen->root,
639                                    XCB_DRI2_DRIVER_TYPE_DRI);
640 
641    xfixes_query =
642       xcb_xfixes_query_version_reply (dri2_dpy->conn,
643 				      xfixes_query_cookie, &error);
644    if (xfixes_query == NULL ||
645        error != NULL || xfixes_query->major_version < 2) {
646       _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
647       free(error);
648       return EGL_FALSE;
649    }
650    free(xfixes_query);
651 
652    dri2_query =
653       xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
654    if (dri2_query == NULL || error != NULL) {
655       _eglLog(_EGL_WARNING, "DRI2: failed to query version");
656       free(error);
657       return EGL_FALSE;
658    }
659    dri2_dpy->dri2_major = dri2_query->major_version;
660    dri2_dpy->dri2_minor = dri2_query->minor_version;
661    free(dri2_query);
662 
663    connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
664    if (connect == NULL ||
665        connect->driver_name_length + connect->device_name_length == 0) {
666       _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
667       return EGL_FALSE;
668    }
669 
670    device_name = xcb_dri2_connect_device_name (connect);
671 
672    dri2_dpy->fd = loader_open_device(device_name);
673    if (dri2_dpy->fd == -1) {
674       _eglLog(_EGL_WARNING,
675               "DRI2: could not open %s (%s)", device_name, strerror(errno));
676       free(connect);
677       return EGL_FALSE;
678    }
679 
680    if (!dri2_x11_local_authenticate(dri2_dpy)) {
681       close(dri2_dpy->fd);
682       free(connect);
683       return EGL_FALSE;
684    }
685 
686    driver_name = xcb_dri2_connect_driver_name (connect);
687 
688    /* If Mesa knows about the appropriate driver for this fd, then trust it.
689     * Otherwise, default to the server's value.
690     */
691    loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
692    if (loader_driver_name) {
693       dri2_dpy->driver_name = loader_driver_name;
694    } else {
695       dri2_dpy->driver_name =
696          strndup(driver_name,
697                  xcb_dri2_connect_driver_name_length(connect));
698    }
699 
700    if (dri2_dpy->driver_name == NULL) {
701       close(dri2_dpy->fd);
702       free(dri2_dpy->driver_name);
703       free(connect);
704       return EGL_FALSE;
705    }
706 
707 #ifdef HAVE_WAYLAND_PLATFORM
708    dri2_dpy->device_name =
709       strndup(device_name,
710               xcb_dri2_connect_device_name_length(connect));
711 #endif
712 
713    free(connect);
714 
715    return EGL_TRUE;
716 }
717 
718 static int
dri2_x11_authenticate(_EGLDisplay * disp,uint32_t id)719 dri2_x11_authenticate(_EGLDisplay *disp, uint32_t id)
720 {
721    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
722 
723    return dri2_x11_do_authenticate(dri2_dpy, id);
724 }
725 
726 static EGLBoolean
dri2_x11_add_configs_for_visuals(struct dri2_egl_display * dri2_dpy,_EGLDisplay * disp,bool supports_preserved)727 dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
728                                  _EGLDisplay *disp, bool supports_preserved)
729 {
730    xcb_depth_iterator_t d;
731    xcb_visualtype_t *visuals;
732    int i, j, count;
733    unsigned int rgba_masks[4];
734    EGLint surface_type;
735    EGLint config_attrs[] = {
736 	   EGL_NATIVE_VISUAL_ID,   0,
737 	   EGL_NATIVE_VISUAL_TYPE, 0,
738 	   EGL_NONE
739    };
740 
741    d = xcb_screen_allowed_depths_iterator(dri2_dpy->screen);
742    count = 0;
743 
744    surface_type =
745       EGL_WINDOW_BIT |
746       EGL_PIXMAP_BIT |
747       EGL_PBUFFER_BIT;
748 
749    if (supports_preserved)
750       surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
751 
752    while (d.rem > 0) {
753       EGLBoolean class_added[6] = { 0, };
754 
755       visuals = xcb_depth_visuals(d.data);
756       for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
757 	 if (class_added[visuals[i]._class])
758 	    continue;
759 
760 	 class_added[visuals[i]._class] = EGL_TRUE;
761 	 for (j = 0; dri2_dpy->driver_configs[j]; j++) {
762             struct dri2_egl_config *dri2_conf;
763             const __DRIconfig *config = dri2_dpy->driver_configs[j];
764 
765             config_attrs[1] = visuals[i].visual_id;
766             config_attrs[3] = visuals[i]._class;
767 
768             rgba_masks[0] = visuals[i].red_mask;
769             rgba_masks[1] = visuals[i].green_mask;
770             rgba_masks[2] = visuals[i].blue_mask;
771             rgba_masks[3] = 0;
772             dri2_conf = dri2_add_config(disp, config, count + 1, surface_type,
773                                         config_attrs, rgba_masks);
774             if (dri2_conf)
775                count++;
776 
777             /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig.
778              * Otherwise it will only match a 32-bit RGBA visual.  On a
779              * composited window manager on X11, this will make all of the
780              * EGLConfigs with destination alpha get blended by the
781              * compositor.  This is probably not what the application
782              * wants... especially on drivers that only have 32-bit RGBA
783              * EGLConfigs! */
784             if (d.data->depth == 24) {
785                rgba_masks[3] =
786                   ~(rgba_masks[0] | rgba_masks[1] | rgba_masks[2]);
787                dri2_conf = dri2_add_config(disp, config, count + 1, surface_type,
788                                            config_attrs, rgba_masks);
789                if (dri2_conf)
790                   count++;
791             }
792 	 }
793       }
794 
795       xcb_depth_next(&d);
796    }
797 
798    if (!count) {
799       _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
800       return EGL_FALSE;
801    }
802 
803    return EGL_TRUE;
804 }
805 
806 static EGLBoolean
dri2_copy_region(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw,xcb_xfixes_region_t region)807 dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
808 		 _EGLSurface *draw, xcb_xfixes_region_t region)
809 {
810    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
811    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
812    enum xcb_dri2_attachment_t render_attachment;
813    xcb_dri2_copy_region_cookie_t cookie;
814 
815    /* No-op for a pixmap or pbuffer surface */
816    if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
817       return EGL_TRUE;
818 
819    if (dri2_dpy->flush)
820       dri2_dpy->flush->flush(dri2_surf->dri_drawable);
821 
822    if (dri2_surf->have_fake_front)
823       render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
824    else
825       render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
826 
827    cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
828 					   dri2_surf->drawable,
829 					   region,
830 					   XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
831 					   render_attachment);
832    free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
833 
834    return EGL_TRUE;
835 }
836 
837 static int64_t
dri2_x11_swap_buffers_msc(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw,int64_t msc,int64_t divisor,int64_t remainder)838 dri2_x11_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
839                           int64_t msc, int64_t divisor, int64_t remainder)
840 {
841    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
842    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
843    uint32_t msc_hi = msc >> 32;
844    uint32_t msc_lo = msc & 0xffffffff;
845    uint32_t divisor_hi = divisor >> 32;
846    uint32_t divisor_lo = divisor & 0xffffffff;
847    uint32_t remainder_hi = remainder >> 32;
848    uint32_t remainder_lo = remainder & 0xffffffff;
849    xcb_dri2_swap_buffers_cookie_t cookie;
850    xcb_dri2_swap_buffers_reply_t *reply;
851    int64_t swap_count = -1;
852 
853    /* No-op for a pixmap or pbuffer surface */
854    if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
855       return 0;
856 
857    if (draw->SwapBehavior == EGL_BUFFER_PRESERVED || !dri2_dpy->swap_available)
858       return dri2_copy_region(drv, disp, draw, dri2_surf->region) ? 0 : -1;
859 
860    dri2_flush_drawable_for_swapbuffers(disp, draw);
861 
862    cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
863                   msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo);
864 
865    reply = xcb_dri2_swap_buffers_reply(dri2_dpy->conn, cookie, NULL);
866 
867    if (reply) {
868       swap_count = (((int64_t)reply->swap_hi) << 32) | reply->swap_lo;
869       free(reply);
870    }
871 
872    /* Since we aren't watching for the server's invalidate events like we're
873     * supposed to (due to XCB providing no mechanism for filtering the events
874     * the way xlib does), and SwapBuffers is a common cause of invalidate
875     * events, just shove one down to the driver, even though we haven't told
876     * the driver that we're the kind of loader that provides reliable
877     * invalidate events.  This causes the driver to request buffers again at
878     * its next draw, so that we get the correct buffers if a pageflip
879     * happened.  The driver should still be using the viewport hack to catch
880     * window resizes.
881     */
882    if (dri2_dpy->flush &&
883        dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
884       dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
885 
886    return swap_count;
887 }
888 
889 static EGLBoolean
dri2_x11_swap_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw)890 dri2_x11_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
891 {
892    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
893    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
894 
895    if (dri2_dpy->dri2) {
896       if (dri2_x11_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1) {
897           return EGL_TRUE;
898       }
899       /* Swap failed with a window drawable. */
900       _eglError(EGL_BAD_NATIVE_WINDOW, __func__);
901       return EGL_FALSE;
902    } else {
903       assert(dri2_dpy->swrast);
904 
905       dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
906       return EGL_TRUE;
907    }
908 }
909 
910 static EGLBoolean
dri2_x11_swap_buffers_region(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw,EGLint numRects,const EGLint * rects)911 dri2_x11_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp,
912                              _EGLSurface *draw,
913                              EGLint numRects, const EGLint *rects)
914 {
915    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
916    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
917    EGLBoolean ret;
918    xcb_xfixes_region_t region;
919    xcb_rectangle_t rectangles[16];
920    int i;
921 
922    if (numRects > (int)ARRAY_SIZE(rectangles))
923       return dri2_copy_region(drv, disp, draw, dri2_surf->region);
924 
925    for (i = 0; i < numRects; i++) {
926       rectangles[i].x = rects[i * 4];
927       rectangles[i].y = dri2_surf->base.Height - rects[i * 4 + 1] - rects[i * 4 + 3];
928       rectangles[i].width = rects[i * 4 + 2];
929       rectangles[i].height = rects[i * 4 + 3];
930    }
931 
932    region = xcb_generate_id(dri2_dpy->conn);
933    xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
934    ret = dri2_copy_region(drv, disp, draw, region);
935    xcb_xfixes_destroy_region(dri2_dpy->conn, region);
936 
937    return ret;
938 }
939 
940 static EGLBoolean
dri2_x11_post_sub_buffer(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw,EGLint x,EGLint y,EGLint width,EGLint height)941 dri2_x11_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
942 		     EGLint x, EGLint y, EGLint width, EGLint height)
943 {
944    const EGLint rect[4] = { x, y, width, height };
945 
946    if (x < 0 || y < 0 || width < 0 || height < 0)
947       _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
948 
949    return dri2_x11_swap_buffers_region(drv, disp, draw, 1, rect);
950 }
951 
952 static EGLBoolean
dri2_x11_swap_interval(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)953 dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
954                        EGLint interval)
955 {
956    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
957    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
958 
959    if (interval > surf->Config->MaxSwapInterval)
960       interval = surf->Config->MaxSwapInterval;
961    else if (interval < surf->Config->MinSwapInterval)
962       interval = surf->Config->MinSwapInterval;
963 
964    if (interval != surf->SwapInterval && dri2_dpy->swap_available)
965       xcb_dri2_swap_interval(dri2_dpy->conn, dri2_surf->drawable, interval);
966 
967    surf->SwapInterval = interval;
968 
969    return EGL_TRUE;
970 }
971 
972 static EGLBoolean
dri2_x11_copy_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)973 dri2_x11_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
974                       void *native_pixmap_target)
975 {
976    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
977    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
978    xcb_gcontext_t gc;
979    xcb_pixmap_t target;
980 
981    STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
982    target = (uintptr_t) native_pixmap_target;
983 
984    (void) drv;
985 
986    dri2_dpy->flush->flush(dri2_surf->dri_drawable);
987 
988    gc = xcb_generate_id(dri2_dpy->conn);
989    xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
990    xcb_copy_area(dri2_dpy->conn,
991 		  dri2_surf->drawable,
992 		  target,
993 		  gc,
994 		  0, 0,
995 		  0, 0,
996 		  dri2_surf->base.Width,
997 		  dri2_surf->base.Height);
998    xcb_free_gc(dri2_dpy->conn, gc);
999 
1000    return EGL_TRUE;
1001 }
1002 
1003 static _EGLImage *
dri2_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)1004 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
1005 			     EGLClientBuffer buffer, const EGLint *attr_list)
1006 {
1007    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1008    struct dri2_egl_image *dri2_img;
1009    unsigned int attachments[1];
1010    xcb_drawable_t drawable;
1011    xcb_dri2_get_buffers_cookie_t buffers_cookie;
1012    xcb_dri2_get_buffers_reply_t *buffers_reply;
1013    xcb_dri2_dri2_buffer_t *buffers;
1014    xcb_get_geometry_cookie_t geometry_cookie;
1015    xcb_get_geometry_reply_t *geometry_reply;
1016    xcb_generic_error_t *error;
1017    int stride, format;
1018 
1019    (void) ctx;
1020 
1021    drawable = (xcb_drawable_t) (uintptr_t) buffer;
1022    xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
1023    attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
1024    buffers_cookie =
1025       xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
1026 				      drawable, 1, 1, attachments);
1027    geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
1028    buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
1029 					       buffers_cookie, NULL);
1030    if (buffers_reply == NULL)
1031      return NULL;
1032 
1033    buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
1034    if (buffers == NULL) {
1035       return NULL;
1036    }
1037 
1038    geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
1039 					    geometry_cookie, &error);
1040    if (geometry_reply == NULL || error != NULL) {
1041       _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
1042       free(error);
1043       free(buffers_reply);
1044       return NULL;
1045    }
1046 
1047    switch (geometry_reply->depth) {
1048    case 16:
1049       format = __DRI_IMAGE_FORMAT_RGB565;
1050       break;
1051    case 24:
1052       format = __DRI_IMAGE_FORMAT_XRGB8888;
1053       break;
1054    case 32:
1055       format = __DRI_IMAGE_FORMAT_ARGB8888;
1056       break;
1057    default:
1058       _eglError(EGL_BAD_PARAMETER,
1059 		"dri2_create_image_khr: unsupported pixmap depth");
1060       free(buffers_reply);
1061       free(geometry_reply);
1062       return NULL;
1063    }
1064 
1065    dri2_img = malloc(sizeof *dri2_img);
1066    if (!dri2_img) {
1067       free(buffers_reply);
1068       free(geometry_reply);
1069       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1070       return EGL_NO_IMAGE_KHR;
1071    }
1072 
1073    if (!_eglInitImage(&dri2_img->base, disp)) {
1074       free(buffers_reply);
1075       free(geometry_reply);
1076       free(dri2_img);
1077       return EGL_NO_IMAGE_KHR;
1078    }
1079 
1080    stride = buffers[0].pitch / buffers[0].cpp;
1081    dri2_img->dri_image =
1082       dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1083 					   buffers_reply->width,
1084 					   buffers_reply->height,
1085 					   format,
1086 					   buffers[0].name,
1087 					   stride,
1088 					   dri2_img);
1089 
1090    free(buffers_reply);
1091    free(geometry_reply);
1092 
1093    return &dri2_img->base;
1094 }
1095 
1096 static _EGLImage *
dri2_x11_create_image_khr(_EGLDriver * drv,_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)1097 dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
1098 			  _EGLContext *ctx, EGLenum target,
1099 			  EGLClientBuffer buffer, const EGLint *attr_list)
1100 {
1101    (void) drv;
1102 
1103    switch (target) {
1104    case EGL_NATIVE_PIXMAP_KHR:
1105       return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
1106    default:
1107       return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
1108    }
1109 }
1110 
1111 static EGLBoolean
dri2_x11_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)1112 dri2_x11_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
1113                          EGLuint64KHR *ust, EGLuint64KHR *msc,
1114                          EGLuint64KHR *sbc)
1115 {
1116    struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);
1117    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
1118    xcb_dri2_get_msc_cookie_t cookie;
1119    xcb_dri2_get_msc_reply_t *reply;
1120 
1121    cookie = xcb_dri2_get_msc(dri2_dpy->conn, dri2_surf->drawable);
1122    reply = xcb_dri2_get_msc_reply(dri2_dpy->conn, cookie, NULL);
1123 
1124    if (!reply) {
1125       _eglError(EGL_BAD_ACCESS, __func__);
1126       return EGL_FALSE;
1127    }
1128 
1129    *ust = ((EGLuint64KHR) reply->ust_hi << 32) | reply->ust_lo;
1130    *msc = ((EGLuint64KHR) reply->msc_hi << 32) | reply->msc_lo;
1131    *sbc = ((EGLuint64KHR) reply->sbc_hi << 32) | reply->sbc_lo;
1132    free(reply);
1133 
1134    return EGL_TRUE;
1135 }
1136 
1137 static struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
1138    .authenticate = NULL,
1139    .create_window_surface = dri2_x11_create_window_surface,
1140    .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1141    .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1142    .destroy_surface = dri2_x11_destroy_surface,
1143    .create_image = dri2_fallback_create_image_khr,
1144    .swap_interval = dri2_fallback_swap_interval,
1145    .swap_buffers = dri2_x11_swap_buffers,
1146    .swap_buffers_region = dri2_fallback_swap_buffers_region,
1147    .post_sub_buffer = dri2_fallback_post_sub_buffer,
1148    .copy_buffers = dri2_x11_copy_buffers,
1149    .query_buffer_age = dri2_fallback_query_buffer_age,
1150    .query_surface = dri2_query_surface,
1151    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1152    .get_sync_values = dri2_fallback_get_sync_values,
1153    .get_dri_drawable = dri2_surface_get_dri_drawable,
1154 };
1155 
1156 static struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
1157    .authenticate = dri2_x11_authenticate,
1158    .create_window_surface = dri2_x11_create_window_surface,
1159    .create_pixmap_surface = dri2_x11_create_pixmap_surface,
1160    .create_pbuffer_surface = dri2_x11_create_pbuffer_surface,
1161    .destroy_surface = dri2_x11_destroy_surface,
1162    .create_image = dri2_x11_create_image_khr,
1163    .swap_interval = dri2_x11_swap_interval,
1164    .swap_buffers = dri2_x11_swap_buffers,
1165    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
1166    .swap_buffers_region = dri2_x11_swap_buffers_region,
1167    .post_sub_buffer = dri2_x11_post_sub_buffer,
1168    .copy_buffers = dri2_x11_copy_buffers,
1169    .query_buffer_age = dri2_fallback_query_buffer_age,
1170    .query_surface = dri2_query_surface,
1171    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1172    .get_sync_values = dri2_x11_get_sync_values,
1173    .get_dri_drawable = dri2_surface_get_dri_drawable,
1174 };
1175 
1176 static const __DRIswrastLoaderExtension swrast_loader_extension = {
1177    .base = { __DRI_SWRAST_LOADER, 1 },
1178 
1179    .getDrawableInfo = swrastGetDrawableInfo,
1180    .putImage        = swrastPutImage,
1181    .getImage        = swrastGetImage,
1182 };
1183 
1184 static const __DRIextension *swrast_loader_extensions[] = {
1185    &swrast_loader_extension.base,
1186    NULL,
1187 };
1188 
1189 static EGLBoolean
dri2_get_xcb_connection(_EGLDriver * drv,_EGLDisplay * disp,struct dri2_egl_display * dri2_dpy)1190 dri2_get_xcb_connection(_EGLDriver *drv, _EGLDisplay *disp,
1191                         struct dri2_egl_display *dri2_dpy)
1192 {
1193    xcb_screen_iterator_t s;
1194    int screen = 0;
1195    const char *msg;
1196 
1197    disp->DriverData = (void *) dri2_dpy;
1198    if (disp->PlatformDisplay == NULL) {
1199       dri2_dpy->conn = xcb_connect(NULL, &screen);
1200       dri2_dpy->own_device = true;
1201    } else {
1202       Display *dpy = disp->PlatformDisplay;
1203 
1204       dri2_dpy->conn = XGetXCBConnection(dpy);
1205       screen = DefaultScreen(dpy);
1206    }
1207 
1208    if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) {
1209       msg = "xcb_connect failed";
1210       goto disconnect;
1211    }
1212 
1213    s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
1214    dri2_dpy->screen = get_xcb_screen(s, screen);
1215    if (!dri2_dpy->screen) {
1216       msg = "failed to get xcb screen";
1217       goto disconnect;
1218    }
1219 
1220    return EGL_TRUE;
1221 disconnect:
1222    if (disp->PlatformDisplay == NULL)
1223       xcb_disconnect(dri2_dpy->conn);
1224 
1225    return _eglError(EGL_BAD_ALLOC, msg);
1226 }
1227 
1228 static EGLBoolean
dri2_initialize_x11_swrast(_EGLDriver * drv,_EGLDisplay * disp)1229 dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
1230 {
1231    struct dri2_egl_display *dri2_dpy;
1232 
1233    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1234    if (!dri2_dpy)
1235       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1236 
1237    if (!dri2_get_xcb_connection(drv, disp, dri2_dpy))
1238       goto cleanup_dpy;
1239 
1240    /*
1241     * Every hardware driver_name is set using strdup. Doing the same in
1242     * here will allow is to simply free the memory at dri2_terminate().
1243     */
1244    dri2_dpy->fd = -1;
1245    dri2_dpy->driver_name = strdup("swrast");
1246    if (!dri2_load_driver_swrast(disp))
1247       goto cleanup_conn;
1248 
1249    dri2_dpy->loader_extensions = swrast_loader_extensions;
1250 
1251    if (!dri2_create_screen(disp))
1252       goto cleanup_driver;
1253 
1254    if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))
1255       goto cleanup_configs;
1256 
1257    /* Fill vtbl last to prevent accidentally calling virtual function during
1258     * initialization.
1259     */
1260    dri2_dpy->vtbl = &dri2_x11_swrast_display_vtbl;
1261 
1262    return EGL_TRUE;
1263 
1264  cleanup_configs:
1265    _eglCleanupDisplay(disp);
1266    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1267  cleanup_driver:
1268    dlclose(dri2_dpy->driver);
1269  cleanup_conn:
1270    free(dri2_dpy->driver_name);
1271    if (disp->PlatformDisplay == NULL)
1272       xcb_disconnect(dri2_dpy->conn);
1273  cleanup_dpy:
1274    free(dri2_dpy);
1275    disp->DriverData = NULL;
1276 
1277    return EGL_FALSE;
1278 }
1279 
1280 static void
dri2_x11_setup_swap_interval(struct dri2_egl_display * dri2_dpy)1281 dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
1282 {
1283    GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1284    int arbitrary_max_interval = 1000;
1285 
1286    /* default behavior for no SwapBuffers support: no vblank syncing
1287     * either.
1288     */
1289    dri2_dpy->min_swap_interval = 0;
1290    dri2_dpy->max_swap_interval = 0;
1291 
1292    if (!dri2_dpy->swap_available)
1293       return;
1294 
1295    /* If we do have swapbuffers, then we can support pretty much any swap
1296     * interval, but we allow driconf to override applications.
1297     */
1298    if (dri2_dpy->config)
1299       dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
1300                                      "vblank_mode", &vblank_mode);
1301    switch (vblank_mode) {
1302    case DRI_CONF_VBLANK_NEVER:
1303       dri2_dpy->min_swap_interval = 0;
1304       dri2_dpy->max_swap_interval = 0;
1305       dri2_dpy->default_swap_interval = 0;
1306       break;
1307    case DRI_CONF_VBLANK_ALWAYS_SYNC:
1308       dri2_dpy->min_swap_interval = 1;
1309       dri2_dpy->max_swap_interval = arbitrary_max_interval;
1310       dri2_dpy->default_swap_interval = 1;
1311       break;
1312    case DRI_CONF_VBLANK_DEF_INTERVAL_0:
1313       dri2_dpy->min_swap_interval = 0;
1314       dri2_dpy->max_swap_interval = arbitrary_max_interval;
1315       dri2_dpy->default_swap_interval = 0;
1316       break;
1317    default:
1318    case DRI_CONF_VBLANK_DEF_INTERVAL_1:
1319       dri2_dpy->min_swap_interval = 0;
1320       dri2_dpy->max_swap_interval = arbitrary_max_interval;
1321       dri2_dpy->default_swap_interval = 1;
1322       break;
1323    }
1324 }
1325 
1326 #ifdef HAVE_DRI3
1327 
1328 static const __DRIextension *dri3_image_loader_extensions[] = {
1329    &dri3_image_loader_extension.base,
1330    &image_lookup_extension.base,
1331    &use_invalidate.base,
1332    NULL,
1333 };
1334 
1335 static EGLBoolean
dri2_initialize_x11_dri3(_EGLDriver * drv,_EGLDisplay * disp)1336 dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)
1337 {
1338    struct dri2_egl_display *dri2_dpy;
1339 
1340    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1341    if (!dri2_dpy)
1342       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1343 
1344    if (!dri2_get_xcb_connection(drv, disp, dri2_dpy))
1345       goto cleanup_dpy;
1346 
1347    if (!dri3_x11_connect(dri2_dpy))
1348       goto cleanup_conn;
1349 
1350    if (!dri2_load_driver_dri3(disp))
1351       goto cleanup_conn;
1352 
1353    dri2_dpy->loader_extensions = dri3_image_loader_extensions;
1354 
1355    dri2_dpy->swap_available = true;
1356    dri2_dpy->invalidate_available = true;
1357 
1358    if (!dri2_create_screen(disp))
1359       goto cleanup_fd;
1360 
1361    dri2_x11_setup_swap_interval(dri2_dpy);
1362 
1363    if (!dri2_dpy->is_different_gpu)
1364       disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1365    disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1366    disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1367    disp->Extensions.EXT_buffer_age = EGL_TRUE;
1368 
1369    dri2_set_WL_bind_wayland_display(drv, disp);
1370 
1371    if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false))
1372       goto cleanup_configs;
1373 
1374    dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
1375    dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
1376    dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
1377    dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;
1378    dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;
1379    dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;
1380 
1381    /* Fill vtbl last to prevent accidentally calling virtual function during
1382     * initialization.
1383     */
1384    dri2_dpy->vtbl = &dri3_x11_display_vtbl;
1385 
1386    _eglLog(_EGL_INFO, "Using DRI3");
1387 
1388    return EGL_TRUE;
1389 
1390  cleanup_configs:
1391    _eglCleanupDisplay(disp);
1392    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1393    dlclose(dri2_dpy->driver);
1394  cleanup_fd:
1395    close(dri2_dpy->fd);
1396  cleanup_conn:
1397    if (disp->PlatformDisplay == NULL)
1398       xcb_disconnect(dri2_dpy->conn);
1399  cleanup_dpy:
1400    free(dri2_dpy);
1401    disp->DriverData = NULL;
1402 
1403    return EGL_FALSE;
1404 }
1405 #endif
1406 
1407 static const __DRIdri2LoaderExtension dri2_loader_extension_old = {
1408    .base = { __DRI_DRI2_LOADER, 2 },
1409 
1410    .getBuffers           = dri2_x11_get_buffers,
1411    .flushFrontBuffer     = dri2_x11_flush_front_buffer,
1412    .getBuffersWithFormat = NULL,
1413 };
1414 
1415 static const __DRIdri2LoaderExtension dri2_loader_extension = {
1416    .base = { __DRI_DRI2_LOADER, 3 },
1417 
1418    .getBuffers           = dri2_x11_get_buffers,
1419    .flushFrontBuffer     = dri2_x11_flush_front_buffer,
1420    .getBuffersWithFormat = dri2_x11_get_buffers_with_format,
1421 };
1422 
1423 static const __DRIextension *dri2_loader_extensions_old[] = {
1424    &dri2_loader_extension_old.base,
1425    &image_lookup_extension.base,
1426    NULL,
1427 };
1428 
1429 static const __DRIextension *dri2_loader_extensions[] = {
1430    &dri2_loader_extension.base,
1431    &image_lookup_extension.base,
1432    NULL,
1433 };
1434 
1435 static EGLBoolean
dri2_initialize_x11_dri2(_EGLDriver * drv,_EGLDisplay * disp)1436 dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
1437 {
1438    struct dri2_egl_display *dri2_dpy;
1439 
1440    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1441    if (!dri2_dpy)
1442       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1443 
1444    if (!dri2_get_xcb_connection(drv, disp, dri2_dpy))
1445       goto cleanup_dpy;
1446 
1447    if (!dri2_x11_connect(dri2_dpy))
1448       goto cleanup_conn;
1449 
1450    if (!dri2_load_driver(disp))
1451       goto cleanup_fd;
1452 
1453    if (dri2_dpy->dri2_minor >= 1)
1454       dri2_dpy->loader_extensions = dri2_loader_extensions;
1455    else
1456       dri2_dpy->loader_extensions = dri2_loader_extensions_old;
1457 
1458    dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
1459    dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
1460 
1461    if (!dri2_create_screen(disp))
1462       goto cleanup_driver;
1463 
1464    dri2_x11_setup_swap_interval(dri2_dpy);
1465 
1466    disp->Extensions.KHR_image_pixmap = EGL_TRUE;
1467    disp->Extensions.NOK_swap_region = EGL_TRUE;
1468    disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
1469    disp->Extensions.NV_post_sub_buffer = EGL_TRUE;
1470    disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
1471 
1472    dri2_set_WL_bind_wayland_display(drv, disp);
1473 
1474    if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true))
1475       goto cleanup_configs;
1476 
1477    /* Fill vtbl last to prevent accidentally calling virtual function during
1478     * initialization.
1479     */
1480    dri2_dpy->vtbl = &dri2_x11_display_vtbl;
1481 
1482    _eglLog(_EGL_INFO, "Using DRI2");
1483 
1484    return EGL_TRUE;
1485 
1486  cleanup_configs:
1487    _eglCleanupDisplay(disp);
1488    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1489  cleanup_driver:
1490    dlclose(dri2_dpy->driver);
1491  cleanup_fd:
1492    close(dri2_dpy->fd);
1493  cleanup_conn:
1494    if (disp->PlatformDisplay == NULL)
1495       xcb_disconnect(dri2_dpy->conn);
1496  cleanup_dpy:
1497    free(dri2_dpy);
1498    disp->DriverData = NULL;
1499 
1500    return EGL_FALSE;
1501 }
1502 
1503 EGLBoolean
dri2_initialize_x11(_EGLDriver * drv,_EGLDisplay * disp)1504 dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
1505 {
1506    EGLBoolean initialized = EGL_FALSE;
1507 
1508    if (!getenv("LIBGL_ALWAYS_SOFTWARE")) {
1509 #ifdef HAVE_DRI3
1510       if (!getenv("LIBGL_DRI3_DISABLE"))
1511          initialized = dri2_initialize_x11_dri3(drv, disp);
1512 #endif
1513 
1514       if (!initialized)
1515          initialized = dri2_initialize_x11_dri2(drv, disp);
1516    }
1517 
1518    if (!initialized)
1519       initialized = dri2_initialize_x11_swrast(drv, disp);
1520 
1521    return initialized;
1522 }
1523 
1524