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