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