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