• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2008 George Sapountzis
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, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
25 
26 #include <xcb/xcb.h>
27 #include <xcb/xproto.h>
28 #include <xcb/shm.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xlib-xcb.h>
31 #include "glxclient.h"
32 #include <dlfcn.h>
33 #include "dri_common.h"
34 #include "drisw_priv.h"
35 #include "dri3_priv.h"
36 #include <X11/extensions/shmproto.h>
37 #include <assert.h>
38 #include <vulkan/vulkan_core.h>
39 #include <vulkan/vulkan_xcb.h>
40 #include "util/u_debug.h"
41 #include "kopper_interface.h"
42 #include "loader_dri_helper.h"
43 
44 static int xshm_error = 0;
45 static int xshm_opcode = -1;
46 
47 /**
48  * Catches potential Xlib errors.
49  */
50 static int
handle_xerror(Display * dpy,XErrorEvent * event)51 handle_xerror(Display *dpy, XErrorEvent *event)
52 {
53    (void) dpy;
54 
55    assert(xshm_opcode != -1);
56    if (event->request_code != xshm_opcode)
57       return 0;
58 
59    xshm_error = event->error_code;
60    return 0;
61 }
62 
63 static Bool
XCreateDrawable(struct drisw_drawable * pdp,int shmid,Display * dpy)64 XCreateDrawable(struct drisw_drawable * pdp, int shmid, Display * dpy)
65 {
66    if (pdp->ximage) {
67       XDestroyImage(pdp->ximage);
68       pdp->ximage = NULL;
69       if ((pdp->shminfo.shmid > 0) && (shmid != pdp->shminfo.shmid))
70          XShmDetach(dpy, &pdp->shminfo);
71    }
72 
73    if (!xshm_error && shmid >= 0) {
74       pdp->shminfo.shmid = shmid;
75       pdp->ximage = XShmCreateImage(dpy,
76                                     NULL,
77                                     pdp->xDepth,
78                                     ZPixmap,              /* format */
79                                     NULL,                 /* data */
80                                     &pdp->shminfo,        /* shminfo */
81                                     0, 0);                /* width, height */
82       if (pdp->ximage != NULL) {
83          int (*old_handler)(Display *, XErrorEvent *);
84 
85          /* dispatch pending errors */
86          XSync(dpy, False);
87 
88          old_handler = XSetErrorHandler(handle_xerror);
89          /* This may trigger the X protocol error we're ready to catch: */
90          XShmAttach(dpy, &pdp->shminfo);
91          XSync(dpy, False);
92 
93          if (xshm_error) {
94          /* we are on a remote display, this error is normal, don't print it */
95             XDestroyImage(pdp->ximage);
96             pdp->ximage = NULL;
97          }
98 
99          (void) XSetErrorHandler(old_handler);
100       }
101    }
102 
103    if (pdp->ximage == NULL) {
104       pdp->shminfo.shmid = -1;
105       pdp->ximage = XCreateImage(dpy,
106                                  NULL,
107                                  pdp->xDepth,
108                                  ZPixmap, 0,             /* format, offset */
109                                  NULL,                   /* data */
110                                  0, 0,                   /* width, height */
111                                  32,                     /* bitmap_pad */
112                                  0);                     /* bytes_per_line */
113    }
114 
115   /**
116    * swrast does not handle 24-bit depth with 24 bpp, so let X do the
117    * the conversion for us.
118    */
119   if (pdp->ximage->bits_per_pixel == 24)
120      pdp->ximage->bits_per_pixel = 32;
121 
122    return True;
123 }
124 
125 static void
XDestroyDrawable(struct drisw_drawable * pdp,Display * dpy,XID drawable)126 XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
127 {
128    if (pdp->ximage)
129       XDestroyImage(pdp->ximage);
130 
131    if (pdp->shminfo.shmid > 0)
132       XShmDetach(dpy, &pdp->shminfo);
133 
134    XFreeGC(dpy, pdp->gc);
135 }
136 
137 /**
138  * swrast loader functions
139  */
140 
141 static void
swrastGetDrawableInfo(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)142 swrastGetDrawableInfo(__DRIdrawable * draw,
143                       int *x, int *y, int *w, int *h,
144                       void *loaderPrivate)
145 {
146    struct drisw_drawable *pdp = loaderPrivate;
147    __GLXDRIdrawable *pdraw = &(pdp->base);
148    Display *dpy = pdraw->psc->dpy;
149    Drawable drawable;
150 
151    Window root;
152    unsigned uw, uh, bw, depth;
153 
154    drawable = pdraw->xDrawable;
155 
156    XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth);
157    *w = uw;
158    *h = uh;
159 }
160 
161 /**
162  * Align renderbuffer pitch.
163  *
164  * This should be chosen by the driver and the loader (libGL, xserver/glx)
165  * should use the driver provided pitch.
166  *
167  * It seems that the xorg loader (that is the xserver loading swrast_dri for
168  * indirect rendering, not client-side libGL) requires that the pitch is
169  * exactly the image width padded to 32 bits. XXX
170  *
171  * The above restriction can probably be overcome by using ScratchPixmap and
172  * CopyArea in the xserver, similar to ShmPutImage, and setting the width of
173  * the scratch pixmap to 'pitch / cpp'.
174  */
175 static inline int
bytes_per_line(unsigned pitch_bits,unsigned mul)176 bytes_per_line(unsigned pitch_bits, unsigned mul)
177 {
178    unsigned mask = mul - 1;
179 
180    return ((pitch_bits + mask) & ~mask) / 8;
181 }
182 
183 static void
swrastXPutImage(__DRIdrawable * draw,int op,int srcx,int srcy,int x,int y,int w,int h,int stride,int shmid,char * data,void * loaderPrivate)184 swrastXPutImage(__DRIdrawable * draw, int op,
185                 int srcx, int srcy, int x, int y,
186                 int w, int h, int stride,
187                 int shmid, char *data, void *loaderPrivate)
188 {
189    struct drisw_drawable *pdp = loaderPrivate;
190    __GLXDRIdrawable *pdraw = &(pdp->base);
191    Display *dpy = pdraw->psc->dpy;
192    Drawable drawable;
193    XImage *ximage;
194    GC gc = pdp->gc;
195 
196    if (!pdp->ximage || shmid != pdp->shminfo.shmid) {
197       if (!XCreateDrawable(pdp, shmid, dpy))
198          return;
199    }
200 
201    drawable = pdraw->xDrawable;
202    ximage = pdp->ximage;
203    ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
204    ximage->data = data;
205 
206    ximage->width = ximage->bytes_per_line / ((ximage->bits_per_pixel + 7)/ 8);
207    ximage->height = h;
208 
209    if (pdp->shminfo.shmid >= 0) {
210       XShmPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h, False);
211       XSync(dpy, False);
212    } else {
213       XPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h);
214    }
215    ximage->data = NULL;
216 }
217 
218 static void
swrastPutImageShm(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,int shmid,char * shmaddr,unsigned offset,void * loaderPrivate)219 swrastPutImageShm(__DRIdrawable * draw, int op,
220                   int x, int y, int w, int h, int stride,
221                   int shmid, char *shmaddr, unsigned offset,
222                   void *loaderPrivate)
223 {
224    struct drisw_drawable *pdp = loaderPrivate;
225 
226    if (!pdp)
227       return;
228 
229    pdp->shminfo.shmaddr = shmaddr;
230    swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, shmid,
231                    shmaddr + offset, loaderPrivate);
232 }
233 
234 static void
swrastPutImageShm2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,int shmid,char * shmaddr,unsigned offset,void * loaderPrivate)235 swrastPutImageShm2(__DRIdrawable * draw, int op,
236                    int x, int y,
237                    int w, int h, int stride,
238                    int shmid, char *shmaddr, unsigned offset,
239                    void *loaderPrivate)
240 {
241    struct drisw_drawable *pdp = loaderPrivate;
242 
243    if (!pdp)
244       return;
245 
246    pdp->shminfo.shmaddr = shmaddr;
247    swrastXPutImage(draw, op, x, 0, x, y, w, h, stride, shmid,
248                    shmaddr + offset, loaderPrivate);
249 }
250 
251 static void
swrastPutImage2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)252 swrastPutImage2(__DRIdrawable * draw, int op,
253                 int x, int y, int w, int h, int stride,
254                 char *data, void *loaderPrivate)
255 {
256    if (!loaderPrivate)
257       return;
258 
259    swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, -1,
260                    data, loaderPrivate);
261 }
262 
263 static void
swrastPutImage(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)264 swrastPutImage(__DRIdrawable * draw, int op,
265                int x, int y, int w, int h,
266                char *data, void *loaderPrivate)
267 {
268    if (!loaderPrivate)
269       return;
270 
271    swrastXPutImage(draw, op, 0, 0, x, y, w, h, 0, -1,
272                    data, loaderPrivate);
273 }
274 
275 static void
swrastGetImage2(__DRIdrawable * read,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)276 swrastGetImage2(__DRIdrawable * read,
277                 int x, int y, int w, int h, int stride,
278                 char *data, void *loaderPrivate)
279 {
280    struct drisw_drawable *prp = loaderPrivate;
281    __GLXDRIdrawable *pread = &(prp->base);
282    Display *dpy = pread->psc->dpy;
283    Drawable readable;
284    XImage *ximage;
285 
286    if (!prp->ximage || prp->shminfo.shmid >= 0) {
287       if (!XCreateDrawable(prp, -1, dpy))
288          return;
289    }
290 
291    readable = pread->xDrawable;
292 
293    ximage = prp->ximage;
294    ximage->data = data;
295    ximage->width = w;
296    ximage->height = h;
297    ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
298 
299    XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
300 
301    ximage->data = NULL;
302 }
303 
304 static void
swrastGetImage(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)305 swrastGetImage(__DRIdrawable * read,
306                int x, int y, int w, int h,
307                char *data, void *loaderPrivate)
308 {
309    swrastGetImage2(read, x, y, w, h, 0, data, loaderPrivate);
310 }
311 
312 static GLboolean
swrastGetImageShm2(__DRIdrawable * read,int x,int y,int w,int h,int shmid,void * loaderPrivate)313 swrastGetImageShm2(__DRIdrawable * read,
314                    int x, int y, int w, int h,
315                    int shmid, void *loaderPrivate)
316 {
317    struct drisw_drawable *prp = loaderPrivate;
318    __GLXDRIdrawable *pread = &(prp->base);
319    Display *dpy = pread->psc->dpy;
320    Drawable readable;
321    XImage *ximage;
322 
323    if (!prp->ximage || shmid != prp->shminfo.shmid) {
324       if (!XCreateDrawable(prp, shmid, dpy))
325          return GL_FALSE;
326    }
327 
328    if (prp->shminfo.shmid == -1)
329       return GL_FALSE;
330    readable = pread->xDrawable;
331 
332    ximage = prp->ximage;
333    ximage->data = prp->shminfo.shmaddr; /* no offset */
334    ximage->width = w;
335    ximage->height = h;
336    ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
337 
338    XShmGetImage(dpy, readable, ximage, x, y, ~0L);
339    return GL_TRUE;
340 }
341 
342 static void
swrastGetImageShm(__DRIdrawable * read,int x,int y,int w,int h,int shmid,void * loaderPrivate)343 swrastGetImageShm(__DRIdrawable * read,
344                   int x, int y, int w, int h,
345                   int shmid, void *loaderPrivate)
346 {
347    swrastGetImageShm2(read, x, y, w, h, shmid, loaderPrivate);
348 }
349 
350 static const __DRIswrastLoaderExtension swrastLoaderExtension_shm = {
351    .base = {__DRI_SWRAST_LOADER, 6 },
352 
353    .getDrawableInfo     = swrastGetDrawableInfo,
354    .putImage            = swrastPutImage,
355    .getImage            = swrastGetImage,
356    .putImage2           = swrastPutImage2,
357    .getImage2           = swrastGetImage2,
358    .putImageShm         = swrastPutImageShm,
359    .getImageShm         = swrastGetImageShm,
360    .putImageShm2        = swrastPutImageShm2,
361    .getImageShm2        = swrastGetImageShm2,
362 };
363 
364 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
365    .base = {__DRI_SWRAST_LOADER, 3 },
366 
367    .getDrawableInfo     = swrastGetDrawableInfo,
368    .putImage            = swrastPutImage,
369    .getImage            = swrastGetImage,
370    .putImage2           = swrastPutImage2,
371    .getImage2           = swrastGetImage2,
372 };
373 
374 static_assert(sizeof(struct kopper_vk_surface_create_storage) >= sizeof(VkXcbSurfaceCreateInfoKHR), "");
375 
376 static void
kopperSetSurfaceCreateInfo(void * _draw,struct kopper_loader_info * out)377 kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *out)
378 {
379     __GLXDRIdrawable *draw = _draw;
380     VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&out->bos;
381 
382     xcb->sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
383     xcb->pNext = NULL;
384     xcb->flags = 0;
385     xcb->connection = XGetXCBConnection(draw->psc->dpy);
386     xcb->window = draw->xDrawable;
387 }
388 
389 static const __DRIkopperLoaderExtension kopperLoaderExtension = {
390     .base = { __DRI_KOPPER_LOADER, 1 },
391 
392     .SetSurfaceCreateInfo   = kopperSetSurfaceCreateInfo,
393 };
394 
395 static const __DRIextension *loader_extensions_shm[] = {
396    &swrastLoaderExtension_shm.base,
397    &kopperLoaderExtension.base,
398    NULL
399 };
400 
401 static const __DRIextension *loader_extensions_noshm[] = {
402    &swrastLoaderExtension.base,
403    &kopperLoaderExtension.base,
404    NULL
405 };
406 
407 extern const __DRIuseInvalidateExtension dri2UseInvalidate;
408 extern const __DRIbackgroundCallableExtension driBackgroundCallable;
409 
410 static const __DRIextension *kopper_extensions_noshm[] = {
411    &swrastLoaderExtension.base,
412    &kopperLoaderExtension.base,
413    &dri2UseInvalidate.base,
414    &driBackgroundCallable.base,
415    NULL
416 };
417 
418 /**
419  * GLXDRI functions
420  */
421 
422 static void
drisw_destroy_context(struct glx_context * context)423 drisw_destroy_context(struct glx_context *context)
424 {
425    struct drisw_screen *psc = (struct drisw_screen *) context->psc;
426 
427    driReleaseDrawables(context);
428 
429    free((char *) context->extensions);
430 
431    psc->core->destroyContext(context->driContext);
432 
433    free(context);
434 }
435 
436 static int
drisw_bind_context(struct glx_context * context,GLXDrawable draw,GLXDrawable read)437 drisw_bind_context(struct glx_context *context, GLXDrawable draw, GLXDrawable read)
438 {
439    struct drisw_screen *psc = (struct drisw_screen *) context->psc;
440    struct drisw_drawable *pdraw, *pread;
441 
442    pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
443    pread = (struct drisw_drawable *) driFetchDrawable(context, read);
444 
445    driReleaseDrawables(context);
446 
447    if (!psc->core->bindContext(context->driContext,
448                                pdraw ? pdraw->driDrawable : NULL,
449                                pread ? pread->driDrawable : NULL))
450       return GLXBadContext;
451    if (psc->f) {
452       if (pdraw)
453          psc->f->invalidate(pdraw->driDrawable);
454       if (pread && (!pdraw || pread->driDrawable != pdraw->driDrawable))
455          psc->f->invalidate(pread->driDrawable);
456    }
457 
458    return Success;
459 }
460 
461 static void
drisw_unbind_context(struct glx_context * context)462 drisw_unbind_context(struct glx_context *context)
463 {
464    struct drisw_screen *psc = (struct drisw_screen *) context->psc;
465 
466    psc->core->unbindContext(context->driContext);
467 }
468 
469 static void
drisw_wait_gl(struct glx_context * context)470 drisw_wait_gl(struct glx_context *context)
471 {
472    glFinish();
473 }
474 
475 static void
drisw_wait_x(struct glx_context * context)476 drisw_wait_x(struct glx_context *context)
477 {
478    XSync(context->currentDpy, False);
479 }
480 
481 static void
drisw_bind_tex_image(__GLXDRIdrawable * base,int buffer,const int * attrib_list)482 drisw_bind_tex_image(__GLXDRIdrawable *base,
483                      int buffer, const int *attrib_list)
484 {
485    struct glx_context *gc = __glXGetCurrentContext();
486    struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
487    struct drisw_screen *psc;
488 
489    if (pdraw != NULL) {
490       psc = (struct drisw_screen *) base->psc;
491 
492       if (!psc->texBuffer)
493          return;
494 
495       if (psc->texBuffer->base.version >= 2 &&
496           psc->texBuffer->setTexBuffer2 != NULL) {
497          psc->texBuffer->setTexBuffer2(gc->driContext,
498                                        pdraw->base.textureTarget,
499                                        pdraw->base.textureFormat,
500                                        pdraw->driDrawable);
501       }
502       else {
503          psc->texBuffer->setTexBuffer(gc->driContext,
504                                       pdraw->base.textureTarget,
505                                       pdraw->driDrawable);
506       }
507    }
508 }
509 
510 static void
drisw_release_tex_image(__GLXDRIdrawable * base,int buffer)511 drisw_release_tex_image(__GLXDRIdrawable *base, int buffer)
512 {
513    struct glx_context *gc = __glXGetCurrentContext();
514    struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
515    struct drisw_screen *psc;
516 
517    if (pdraw != NULL) {
518       psc = (struct drisw_screen *) base->psc;
519 
520       if (!psc->texBuffer)
521          return;
522 
523       if (psc->texBuffer->base.version >= 3 &&
524           psc->texBuffer->releaseTexBuffer != NULL) {
525          psc->texBuffer->releaseTexBuffer(gc->driContext,
526                                           pdraw->base.textureTarget,
527                                           pdraw->driDrawable);
528       }
529    }
530 }
531 
532 static int
kopper_get_buffer_age(__GLXDRIdrawable * pdraw)533 kopper_get_buffer_age(__GLXDRIdrawable *pdraw)
534 {
535    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
536 
537    if (pdp) {
538       struct drisw_screen *psc = (struct drisw_screen *) pdraw->psc;
539 
540       if (psc->kopper)
541          return psc->kopper->queryBufferAge(pdp->driDrawable);
542    }
543    return 0;
544 }
545 
546 static const struct glx_context_vtable drisw_context_vtable = {
547    .destroy             = drisw_destroy_context,
548    .bind                = drisw_bind_context,
549    .unbind              = drisw_unbind_context,
550    .wait_gl             = drisw_wait_gl,
551    .wait_x              = drisw_wait_x,
552 };
553 
554 static struct glx_context *
drisw_create_context_attribs(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,unsigned num_attribs,const uint32_t * attribs,unsigned * error)555 drisw_create_context_attribs(struct glx_screen *base,
556                              struct glx_config *config_base,
557                              struct glx_context *shareList,
558                              unsigned num_attribs,
559                              const uint32_t *attribs,
560                              unsigned *error)
561 {
562    struct glx_context *pcp, *pcp_shared;
563    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
564    struct drisw_screen *psc = (struct drisw_screen *) base;
565    __DRIcontext *shared = NULL;
566 
567    struct dri_ctx_attribs dca;
568    uint32_t ctx_attribs[2 * 5];
569    unsigned num_ctx_attribs = 0;
570 
571    if (!psc->base.driScreen)
572       return NULL;
573 
574    *error = dri_convert_glx_attribs(num_attribs, attribs, &dca);
575    if (*error != __DRI_CTX_ERROR_SUCCESS)
576       return NULL;
577 
578    /* Check the renderType value */
579    if (!validate_renderType_against_config(config_base, dca.render_type)) {
580       *error = BadValue;
581       return NULL;
582    }
583 
584    if (shareList) {
585       /* We can't share with an indirect context */
586       if (!shareList->isDirect)
587          return NULL;
588 
589       /* The GLX_ARB_create_context_no_error specs say:
590        *
591        *    BadMatch is generated if the value of GLX_CONTEXT_OPENGL_NO_ERROR_ARB
592        *    used to create <share_context> does not match the value of
593        *    GLX_CONTEXT_OPENGL_NO_ERROR_ARB for the context being created.
594        */
595       if (!!shareList->noError != !!dca.no_error) {
596          *error = BadMatch;
597          return NULL;
598       }
599 
600       pcp_shared = (struct glx_context *) shareList;
601       shared = pcp_shared->driContext;
602    }
603 
604    pcp = calloc(1, sizeof *pcp);
605    if (pcp == NULL)
606       return NULL;
607 
608    if (!glx_context_init(pcp, &psc->base, config_base)) {
609       free(pcp);
610       return NULL;
611    }
612 
613    ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
614    ctx_attribs[num_ctx_attribs++] = dca.major_ver;
615    ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
616    ctx_attribs[num_ctx_attribs++] = dca.minor_ver;
617    if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
618       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
619       ctx_attribs[num_ctx_attribs++] = dca.reset;
620    }
621 
622    if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
623        ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
624        ctx_attribs[num_ctx_attribs++] = dca.release;
625    }
626    if (dca.no_error) {
627        ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_NO_ERROR;
628        ctx_attribs[num_ctx_attribs++] = GL_TRUE;
629        pcp->noError = GL_TRUE;
630    }
631 
632    if (dca.flags != 0) {
633       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
634       ctx_attribs[num_ctx_attribs++] = dca.flags;
635    }
636 
637    pcp->renderType = dca.render_type;
638 
639    pcp->driContext =
640       psc->swrast->createContextAttribs(psc->driScreen,
641                                         dca.api,
642                                         config ? config->driConfig : NULL,
643                                         shared,
644                                         num_ctx_attribs / 2,
645                                         ctx_attribs,
646                                         error,
647                                         pcp);
648    *error = dri_context_error_to_glx_error(*error);
649 
650    if (pcp->driContext == NULL) {
651       free(pcp);
652       return NULL;
653    }
654 
655    pcp->vtable = base->context_vtable;
656 
657    return pcp;
658 }
659 
660 static void
driswDestroyDrawable(__GLXDRIdrawable * pdraw)661 driswDestroyDrawable(__GLXDRIdrawable * pdraw)
662 {
663    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
664    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
665 
666    psc->core->destroyDrawable(pdp->driDrawable);
667 
668    XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
669    free(pdp);
670 }
671 
672 static __GLXDRIdrawable *
driswCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * modes)673 driswCreateDrawable(struct glx_screen *base, XID xDrawable,
674                     GLXDrawable drawable, int type,
675                     struct glx_config *modes)
676 {
677    struct drisw_drawable *pdp;
678    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
679    unsigned depth;
680    struct drisw_screen *psc = (struct drisw_screen *) base;
681    const __DRIswrastExtension *swrast = psc->swrast;
682    const __DRIkopperExtension *kopper = psc->kopper;
683    Display *dpy = psc->base.dpy;
684 
685    xcb_connection_t *conn = XGetXCBConnection(dpy);
686    xcb_generic_error_t *error;
687    xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, xDrawable);
688    xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(conn, cookie, &error);
689    if (reply)
690       depth = reply->depth;
691    free(reply);
692    if (!reply || error)
693       return NULL;
694 
695    pdp = calloc(1, sizeof(*pdp));
696    if (!pdp)
697       return NULL;
698 
699    pdp->base.xDrawable = xDrawable;
700    pdp->base.drawable = drawable;
701    pdp->base.psc = &psc->base;
702    pdp->config = modes;
703    pdp->gc = XCreateGC(dpy, xDrawable, 0, NULL);
704    pdp->xDepth = 0;
705 
706    /* Use the visual depth, if this fbconfig corresponds to a visual */
707    if (pdp->config->visualID != 0) {
708       int matches = 0;
709       XVisualInfo *visinfo, template;
710 
711       template.visualid = pdp->config->visualID;
712       template.screen = pdp->config->screen;
713       visinfo = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask,
714                                &template, &matches);
715 
716       if (visinfo && matches) {
717          pdp->xDepth = visinfo->depth;
718          XFree(visinfo);
719       }
720    }
721 
722    /* Otherwise, or if XGetVisualInfo failed, ask the server */
723    if (pdp->xDepth == 0) {
724       pdp->xDepth = depth;
725    }
726 
727    /* Create a new drawable */
728    if (kopper) {
729       pdp->driDrawable =
730          kopper->createNewDrawable(psc->driScreen, config->driConfig, pdp,
731          &(__DRIkopperDrawableInfo){
732             .multiplanes_available = psc->has_multibuffer,
733             .is_pixmap = !(type & GLX_WINDOW_BIT),
734          });
735 
736       pdp->swapInterval = dri_get_initial_swap_interval(psc->driScreen, psc->config);
737       psc->kopper->setSwapInterval(pdp->driDrawable, pdp->swapInterval);
738    }
739    else
740       pdp->driDrawable =
741          swrast->createNewDrawable(psc->driScreen, config->driConfig, pdp);
742 
743    if (!pdp->driDrawable) {
744       XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
745       free(pdp);
746       return NULL;
747    }
748 
749    pdp->base.destroyDrawable = driswDestroyDrawable;
750 
751    return &pdp->base;
752 }
753 
754 static int64_t
driswSwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)755 driswSwapBuffers(__GLXDRIdrawable * pdraw,
756                  int64_t target_msc, int64_t divisor, int64_t remainder,
757                  Bool flush)
758 {
759    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
760    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
761 
762    (void) target_msc;
763    (void) divisor;
764    (void) remainder;
765 
766    if (flush) {
767       glFlush();
768    }
769 
770    if (psc->kopper)
771        return psc->kopper->swapBuffers (pdp->driDrawable, 0);
772 
773    psc->core->swapBuffers(pdp->driDrawable);
774 
775    return 0;
776 }
777 
778 static void
driswCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)779 driswCopySubBuffer(__GLXDRIdrawable * pdraw,
780                    int x, int y, int width, int height, Bool flush)
781 {
782    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
783    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
784 
785    if (flush) {
786       glFlush();
787    }
788 
789    psc->copySubBuffer->copySubBuffer(pdp->driDrawable, x, y, width, height);
790 }
791 
792 static void
driswDestroyScreen(struct glx_screen * base)793 driswDestroyScreen(struct glx_screen *base)
794 {
795    struct drisw_screen *psc = (struct drisw_screen *) base;
796 
797    /* Free the direct rendering per screen data */
798    psc->core->destroyScreen(psc->driScreen);
799    driDestroyConfigs(psc->driver_configs);
800    psc->driScreen = NULL;
801    if (psc->driver)
802       dlclose(psc->driver);
803    free(psc);
804 }
805 
806 static char *
drisw_get_driver_name(struct glx_screen * glx_screen)807 drisw_get_driver_name(struct glx_screen *glx_screen)
808 {
809    struct drisw_screen *psc = (struct drisw_screen *) glx_screen;
810    return strdup(psc->name);
811 }
812 
813 static const struct glx_screen_vtable drisw_screen_vtable = {
814    .create_context         = dri_common_create_context,
815    .create_context_attribs = drisw_create_context_attribs,
816    .query_renderer_integer = drisw_query_renderer_integer,
817    .query_renderer_string  = drisw_query_renderer_string,
818    .get_driver_name        = drisw_get_driver_name,
819 };
820 
821 static void
driswBindExtensions(struct drisw_screen * psc,const __DRIextension ** extensions)822 driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
823 {
824    int i;
825 
826    __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
827    __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
828    __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
829    __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_no_error");
830    __glXEnableDirectExtension(&psc->base, "GLX_EXT_no_config_context");
831 
832    /* DRISW version >= 2 implies support for OpenGL ES. */
833    __glXEnableDirectExtension(&psc->base,
834                               "GLX_EXT_create_context_es_profile");
835    __glXEnableDirectExtension(&psc->base,
836                               "GLX_EXT_create_context_es2_profile");
837 
838    if (psc->copySubBuffer)
839       __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
840 
841    /* FIXME: Figure out what other extensions can be ported here from dri2. */
842    static const struct dri_extension_match exts[] = {
843        { __DRI_TEX_BUFFER, 1, offsetof(struct drisw_screen, texBuffer), true },
844        { __DRI2_RENDERER_QUERY, 1, offsetof(struct drisw_screen, rendererQuery), true },
845        { __DRI2_FLUSH, 1, offsetof(struct drisw_screen, f), true },
846        { __DRI2_CONFIG_QUERY, 1, offsetof(struct drisw_screen, config), true },
847    };
848    loader_bind_extensions(psc, exts, ARRAY_SIZE(exts), extensions);
849 
850    /* Extensions where we don't care about the extension struct */
851    for (i = 0; extensions[i]; i++) {
852       if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
853          __glXEnableDirectExtension(&psc->base,
854                                     "GLX_ARB_create_context_robustness");
855 
856       if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
857           __glXEnableDirectExtension(&psc->base,
858                                      "GLX_ARB_context_flush_control");
859       }
860    }
861 
862    if (psc->texBuffer)
863       __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
864 
865    if (psc->rendererQuery) {
866       __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
867    }
868 
869    if (psc->kopper) {
870        __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
871        __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control");
872        __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
873        __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
874        // This needs to check whether RELAXED is available
875        // __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control_tear");
876    }
877 }
878 
879 static int
check_xshm(Display * dpy)880 check_xshm(Display *dpy)
881 {
882    xcb_connection_t *c = XGetXCBConnection(dpy);
883    xcb_void_cookie_t cookie;
884    xcb_generic_error_t *error;
885    int ret = True;
886    xcb_query_extension_cookie_t shm_cookie;
887    xcb_query_extension_reply_t *shm_reply;
888    bool has_mit_shm;
889 
890    shm_cookie = xcb_query_extension(c, 7, "MIT-SHM");
891    shm_reply = xcb_query_extension_reply(c, shm_cookie, NULL);
892    xshm_opcode = shm_reply->major_opcode;
893 
894    has_mit_shm = shm_reply->present;
895    free(shm_reply);
896    if (!has_mit_shm)
897       return False;
898 
899    cookie = xcb_shm_detach_checked(c, 0);
900    if ((error = xcb_request_check(c, cookie))) {
901       /* BadRequest means we're a remote client. If we were local we'd
902        * expect BadValue since 'info' has an invalid segment name.
903        */
904       if (error->error_code == BadRequest)
905          ret = False;
906       free(error);
907    }
908 
909    return ret;
910 }
911 
912 static int
kopperSetSwapInterval(__GLXDRIdrawable * pdraw,int interval)913 kopperSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
914 {
915    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
916    struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
917 
918    if (!dri_valid_swap_interval(psc->driScreen, psc->config, interval))
919       return GLX_BAD_VALUE;
920 
921    psc->kopper->setSwapInterval(pdp->driDrawable, interval);
922    pdp->swapInterval = interval;
923 
924    return 0;
925 }
926 
927 static int
kopperGetSwapInterval(__GLXDRIdrawable * pdraw)928 kopperGetSwapInterval(__GLXDRIdrawable *pdraw)
929 {
930    struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
931 
932    return pdp->swapInterval;
933 }
934 
935 static struct glx_screen *
driswCreateScreenDriver(int screen,struct glx_display * priv,const char * driver)936 driswCreateScreenDriver(int screen, struct glx_display *priv,
937                         const char *driver)
938 {
939    __GLXDRIscreen *psp;
940    const __DRIconfig **driver_configs;
941    const __DRIextension **extensions;
942    struct drisw_screen *psc;
943    struct glx_config *configs = NULL, *visuals = NULL;
944    const __DRIextension **loader_extensions_local;
945    const struct drisw_display *pdpyp = (struct drisw_display *)priv->driswDisplay;
946 
947    psc = calloc(1, sizeof *psc);
948    if (psc == NULL)
949       return NULL;
950 
951    if (!glx_screen_init(&psc->base, screen, priv)) {
952       free(psc);
953       return NULL;
954    }
955 
956    extensions = driOpenDriver(driver, &psc->driver);
957    if (extensions == NULL)
958       goto handle_error;
959    psc->name = driver;
960 
961    if (pdpyp->zink)
962       loader_extensions_local = kopper_extensions_noshm;
963    else if (!check_xshm(psc->base.dpy))
964       loader_extensions_local = loader_extensions_noshm;
965    else
966       loader_extensions_local = loader_extensions_shm;
967 
968    static const struct dri_extension_match exts[] = {
969        { __DRI_CORE, 1, offsetof(struct drisw_screen, core), false },
970        { __DRI_SWRAST, 4, offsetof(struct drisw_screen, swrast), false },
971        { __DRI_KOPPER, 1, offsetof(struct drisw_screen, kopper), true },
972        { __DRI_COPY_SUB_BUFFER, 1, offsetof(struct drisw_screen, copySubBuffer), true },
973        { __DRI_MESA, 1, offsetof(struct drisw_screen, mesa), false },
974    };
975    if (!loader_bind_extensions(psc, exts, ARRAY_SIZE(exts), extensions))
976       goto handle_error;
977 
978    psc->driScreen =
979       psc->swrast->createNewScreen2(screen, loader_extensions_local,
980                                     extensions,
981                                     &driver_configs, psc);
982    if (psc->driScreen == NULL) {
983       ErrorMessageF("glx: failed to create drisw screen\n");
984       goto handle_error;
985    }
986 
987    extensions = psc->core->getExtensions(psc->driScreen);
988    driswBindExtensions(psc, extensions);
989 
990    configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
991    visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
992 
993    if (!configs || !visuals) {
994        ErrorMessageF("No matching fbConfigs or visuals found\n");
995        goto handle_error;
996    }
997 
998    if (pdpyp->zink) {
999       bool err;
1000       psc->has_multibuffer = dri3_check_multibuffer(priv->dpy, &err);
1001       if (!psc->has_multibuffer &&
1002           !debug_get_bool_option("LIBGL_ALWAYS_SOFTWARE", false) &&
1003           !debug_get_bool_option("LIBGL_KOPPER_DRI2", false)) {
1004          CriticalErrorMessageF("DRI3 not available\n");
1005          goto handle_error;
1006       }
1007    }
1008 
1009    glx_config_destroy_list(psc->base.configs);
1010    psc->base.configs = configs;
1011    glx_config_destroy_list(psc->base.visuals);
1012    psc->base.visuals = visuals;
1013 
1014    psc->driver_configs = driver_configs;
1015 
1016    psc->base.vtable = &drisw_screen_vtable;
1017    psc->base.context_vtable = &drisw_context_vtable;
1018    psp = &psc->vtable;
1019    psc->base.driScreen = psp;
1020    psp->destroyScreen = driswDestroyScreen;
1021    psp->createDrawable = driswCreateDrawable;
1022    psp->swapBuffers = driswSwapBuffers;
1023    psp->bindTexImage = drisw_bind_tex_image;
1024    psp->releaseTexImage = drisw_release_tex_image;
1025 
1026    if (psc->copySubBuffer)
1027       psp->copySubBuffer = driswCopySubBuffer;
1028 
1029    if (psc->kopper) {
1030       psp->getBufferAge = kopper_get_buffer_age;
1031       psp->setSwapInterval = kopperSetSwapInterval;
1032       psp->getSwapInterval = kopperGetSwapInterval;
1033       psp->maxSwapInterval = 1;
1034    }
1035 
1036    return &psc->base;
1037 
1038  handle_error:
1039    if (configs)
1040        glx_config_destroy_list(configs);
1041    if (visuals)
1042        glx_config_destroy_list(visuals);
1043    if (psc->driScreen)
1044        psc->core->destroyScreen(psc->driScreen);
1045    psc->driScreen = NULL;
1046 
1047    if (psc->driver)
1048       dlclose(psc->driver);
1049    glx_screen_cleanup(&psc->base);
1050    free(psc);
1051 
1052    CriticalErrorMessageF("failed to load driver: %s\n", driver);
1053 
1054    return NULL;
1055 }
1056 
1057 static struct glx_screen *
driswCreateScreen(int screen,struct glx_display * priv)1058 driswCreateScreen(int screen, struct glx_display *priv)
1059 {
1060    const struct drisw_display *pdpyp = (struct drisw_display *)priv->driswDisplay;
1061    if (pdpyp->zink && !debug_get_bool_option("LIBGL_KOPPER_DISABLE", false)) {
1062       return driswCreateScreenDriver(screen, priv, "zink");
1063    }
1064 
1065    return driswCreateScreenDriver(screen, priv, "swrast");
1066 }
1067 
1068 /* Called from __glXFreeDisplayPrivate.
1069  */
1070 static void
driswDestroyDisplay(__GLXDRIdisplay * dpy)1071 driswDestroyDisplay(__GLXDRIdisplay * dpy)
1072 {
1073    free(dpy);
1074 }
1075 
1076 /*
1077  * Allocate, initialize and return a __DRIdisplayPrivate object.
1078  * This is called from __glXInitialize() when we are given a new
1079  * display pointer.
1080  */
1081 _X_HIDDEN __GLXDRIdisplay *
driswCreateDisplay(Display * dpy,bool zink)1082 driswCreateDisplay(Display * dpy, bool zink)
1083 {
1084    struct drisw_display *pdpyp;
1085 
1086    pdpyp = malloc(sizeof *pdpyp);
1087    if (pdpyp == NULL)
1088       return NULL;
1089 
1090    pdpyp->base.destroyDisplay = driswDestroyDisplay;
1091    pdpyp->base.createScreen = driswCreateScreen;
1092    pdpyp->zink = zink;
1093 
1094    return &pdpyp->base;
1095 }
1096 
1097 #endif /* GLX_DIRECT_RENDERING */
1098