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
31struct drisw_display
32{
33   __GLXDRIdisplay base;
34};
35
36struct drisw_context
37{
38   struct glx_context base;
39   __DRIcontext *driContext;
40
41};
42
43struct drisw_screen
44{
45   struct glx_screen base;
46
47   __DRIscreen *driScreen;
48   __GLXDRIscreen vtable;
49   const __DRIcoreExtension *core;
50   const __DRIswrastExtension *swrast;
51   const __DRItexBufferExtension *texBuffer;
52
53   const __DRIconfig **driver_configs;
54
55   void *driver;
56};
57
58struct drisw_drawable
59{
60   __GLXDRIdrawable base;
61
62   GC gc;
63   GC swapgc;
64
65   __DRIdrawable *driDrawable;
66   XVisualInfo *visinfo;
67   XImage *ximage;
68};
69
70static Bool
71XCreateDrawable(struct drisw_drawable * pdp,
72                Display * dpy, XID drawable, int visualid)
73{
74   XGCValues gcvalues;
75   long visMask;
76   XVisualInfo visTemp;
77   int num_visuals;
78
79   /* create GC's */
80   pdp->gc = XCreateGC(dpy, drawable, 0, NULL);
81   pdp->swapgc = XCreateGC(dpy, drawable, 0, NULL);
82
83   gcvalues.function = GXcopy;
84   gcvalues.graphics_exposures = False;
85   XChangeGC(dpy, pdp->gc, GCFunction, &gcvalues);
86   XChangeGC(dpy, pdp->swapgc, GCFunction, &gcvalues);
87   XChangeGC(dpy, pdp->swapgc, GCGraphicsExposures, &gcvalues);
88
89   /* visual */
90   visTemp.visualid = visualid;
91   visMask = VisualIDMask;
92   pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals);
93
94   if (!pdp->visinfo || num_visuals == 0)
95      return False;
96
97   /* create XImage */
98   pdp->ximage = XCreateImage(dpy,
99                              pdp->visinfo->visual,
100                              pdp->visinfo->depth,
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   * swrast does not handle 24-bit depth with 24 bpp, so let X do the
109   * the conversion for us.
110   */
111  if (pdp->ximage->bits_per_pixel == 24)
112     pdp->ximage->bits_per_pixel = 32;
113
114   return True;
115}
116
117static void
118XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
119{
120   XDestroyImage(pdp->ximage);
121   XFree(pdp->visinfo);
122
123   XFreeGC(dpy, pdp->gc);
124   XFreeGC(dpy, pdp->swapgc);
125}
126
127/**
128 * swrast loader functions
129 */
130
131static void
132swrastGetDrawableInfo(__DRIdrawable * draw,
133                      int *x, int *y, int *w, int *h,
134                      void *loaderPrivate)
135{
136   struct drisw_drawable *pdp = loaderPrivate;
137   __GLXDRIdrawable *pdraw = &(pdp->base);
138   Display *dpy = pdraw->psc->dpy;
139   Drawable drawable;
140
141   Window root;
142   unsigned uw, uh, bw, depth;
143
144   drawable = pdraw->xDrawable;
145
146   XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth);
147   *w = uw;
148   *h = uh;
149}
150
151/**
152 * Align renderbuffer pitch.
153 *
154 * This should be chosen by the driver and the loader (libGL, xserver/glx)
155 * should use the driver provided pitch.
156 *
157 * It seems that the xorg loader (that is the xserver loading swrast_dri for
158 * indirect rendering, not client-side libGL) requires that the pitch is
159 * exactly the image width padded to 32 bits. XXX
160 *
161 * The above restriction can probably be overcome by using ScratchPixmap and
162 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of
163 * the scratch pixmap to 'pitch / cpp'.
164 */
165static inline int
166bytes_per_line(unsigned pitch_bits, unsigned mul)
167{
168   unsigned mask = mul - 1;
169
170   return ((pitch_bits + mask) & ~mask) / 8;
171}
172
173static void
174swrastPutImage(__DRIdrawable * draw, int op,
175               int x, int y, int w, int h,
176               char *data, void *loaderPrivate)
177{
178   struct drisw_drawable *pdp = loaderPrivate;
179   __GLXDRIdrawable *pdraw = &(pdp->base);
180   Display *dpy = pdraw->psc->dpy;
181   Drawable drawable;
182   XImage *ximage;
183   GC gc;
184
185   switch (op) {
186   case __DRI_SWRAST_IMAGE_OP_DRAW:
187      gc = pdp->gc;
188      break;
189   case __DRI_SWRAST_IMAGE_OP_SWAP:
190      gc = pdp->swapgc;
191      break;
192   default:
193      return;
194   }
195
196   drawable = pdraw->xDrawable;
197
198   ximage = pdp->ximage;
199   ximage->data = data;
200   ximage->width = w;
201   ximage->height = h;
202   ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
203
204   XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h);
205
206   ximage->data = NULL;
207}
208
209static void
210swrastGetImage(__DRIdrawable * read,
211               int x, int y, int w, int h,
212               char *data, void *loaderPrivate)
213{
214   struct drisw_drawable *prp = loaderPrivate;
215   __GLXDRIdrawable *pread = &(prp->base);
216   Display *dpy = pread->psc->dpy;
217   Drawable readable;
218   XImage *ximage;
219
220   readable = pread->xDrawable;
221
222   ximage = prp->ximage;
223   ximage->data = data;
224   ximage->width = w;
225   ximage->height = h;
226   ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
227
228   XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
229
230   ximage->data = NULL;
231}
232
233static const __DRIswrastLoaderExtension swrastLoaderExtension = {
234   {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION},
235   swrastGetDrawableInfo,
236   swrastPutImage,
237   swrastGetImage
238};
239
240static const __DRIextension *loader_extensions[] = {
241   &systemTimeExtension.base,
242   &swrastLoaderExtension.base,
243   NULL
244};
245
246/**
247 * GLXDRI functions
248 */
249
250static void
251drisw_destroy_context(struct glx_context *context)
252{
253   struct drisw_context *pcp = (struct drisw_context *) context;
254   struct drisw_screen *psc = (struct drisw_screen *) context->psc;
255
256   driReleaseDrawables(&pcp->base);
257
258   if (context->extensions)
259      XFree((char *) context->extensions);
260
261   (*psc->core->destroyContext) (pcp->driContext);
262
263   Xfree(pcp);
264}
265
266static int
267drisw_bind_context(struct glx_context *context, struct glx_context *old,
268		   GLXDrawable draw, GLXDrawable read)
269{
270   struct drisw_context *pcp = (struct drisw_context *) context;
271   struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
272   struct drisw_drawable *pdraw, *pread;
273
274   pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
275   pread = (struct drisw_drawable *) driFetchDrawable(context, read);
276
277   driReleaseDrawables(&pcp->base);
278
279   if (pdraw == NULL || pread == NULL)
280      return GLXBadDrawable;
281
282   if ((*psc->core->bindContext) (pcp->driContext,
283				  pdraw->driDrawable, pread->driDrawable))
284      return Success;
285
286   return GLXBadContext;
287}
288
289static void
290drisw_unbind_context(struct glx_context *context, struct glx_context *new)
291{
292   struct drisw_context *pcp = (struct drisw_context *) context;
293   struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
294
295   (*psc->core->unbindContext) (pcp->driContext);
296}
297
298static void
299drisw_bind_tex_image(Display * dpy,
300		    GLXDrawable drawable,
301		    int buffer, const int *attrib_list)
302{
303   struct glx_context *gc = __glXGetCurrentContext();
304   struct drisw_context *pcp = (struct drisw_context *) gc;
305   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
306   struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
307   struct drisw_screen *psc;
308
309   __glXInitialize(dpy);
310
311   if (pdraw != NULL) {
312      psc = (struct drisw_screen *) base->psc;
313
314      if (!psc->texBuffer)
315         return;
316
317      if (psc->texBuffer->base.version >= 2 &&
318        psc->texBuffer->setTexBuffer2 != NULL) {
319	      (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
320					   pdraw->base.textureTarget,
321					   pdraw->base.textureFormat,
322					   pdraw->driDrawable);
323      }
324      else {
325	      (*psc->texBuffer->setTexBuffer) (pcp->driContext,
326					  pdraw->base.textureTarget,
327					  pdraw->driDrawable);
328      }
329   }
330}
331
332static void
333drisw_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
334{
335#if __DRI_TEX_BUFFER_VERSION >= 3
336   struct glx_context *gc = __glXGetCurrentContext();
337   struct dri2_context *pcp = (struct dri2_context *) gc;
338   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
339   struct glx_display *dpyPriv = __glXInitialize(dpy);
340   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
341   struct dri2_screen *psc;
342
343   if (pdraw != NULL) {
344      psc = (struct dri2_screen *) base->psc;
345
346      if (!psc->texBuffer)
347         return;
348
349      if (psc->texBuffer->base.version >= 3 &&
350          psc->texBuffer->releaseTexBuffer != NULL) {
351         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
352                                           pdraw->base.textureTarget,
353                                           pdraw->driDrawable);
354      }
355   }
356#endif
357}
358
359static const struct glx_context_vtable drisw_context_vtable = {
360   drisw_destroy_context,
361   drisw_bind_context,
362   drisw_unbind_context,
363   NULL,
364   NULL,
365   DRI_glXUseXFont,
366   drisw_bind_tex_image,
367   drisw_release_tex_image,
368   NULL, /* get_proc_address */
369};
370
371static struct glx_context *
372drisw_create_context(struct glx_screen *base,
373		     struct glx_config *config_base,
374		     struct glx_context *shareList, int renderType)
375{
376   struct drisw_context *pcp, *pcp_shared;
377   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
378   struct drisw_screen *psc = (struct drisw_screen *) base;
379   __DRIcontext *shared = NULL;
380
381   if (!psc->base.driScreen)
382      return NULL;
383
384   if (shareList) {
385      /* If the shareList context is not a DRISW context, we cannot possibly
386       * create a DRISW context that shares it.
387       */
388      if (shareList->vtable->destroy != drisw_destroy_context) {
389	 return NULL;
390      }
391
392      pcp_shared = (struct drisw_context *) shareList;
393      shared = pcp_shared->driContext;
394   }
395
396   pcp = Xmalloc(sizeof *pcp);
397   if (pcp == NULL)
398      return NULL;
399
400   memset(pcp, 0, sizeof *pcp);
401   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
402      Xfree(pcp);
403      return NULL;
404   }
405
406   pcp->driContext =
407      (*psc->core->createNewContext) (psc->driScreen,
408				      config->driConfig, shared, pcp);
409   if (pcp->driContext == NULL) {
410      Xfree(pcp);
411      return NULL;
412   }
413
414   pcp->base.vtable = &drisw_context_vtable;
415
416   return &pcp->base;
417}
418
419static struct glx_context *
420drisw_create_context_attribs(struct glx_screen *base,
421			     struct glx_config *config_base,
422			     struct glx_context *shareList,
423			     unsigned num_attribs,
424			     const uint32_t *attribs,
425			     unsigned *error)
426{
427   struct drisw_context *pcp, *pcp_shared;
428   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
429   struct drisw_screen *psc = (struct drisw_screen *) base;
430   __DRIcontext *shared = NULL;
431
432   uint32_t minor_ver = 1;
433   uint32_t major_ver = 0;
434   uint32_t flags = 0;
435   unsigned api;
436   int reset = __DRI_CTX_RESET_NO_NOTIFICATION;
437   uint32_t ctx_attribs[2 * 4];
438   unsigned num_ctx_attribs = 0;
439
440   if (!psc->base.driScreen)
441      return NULL;
442
443   if (psc->swrast->base.version < 3)
444      return NULL;
445
446   /* Remap the GLX tokens to DRI2 tokens.
447    */
448   if (!dri2_convert_glx_attribs(num_attribs, attribs,
449				 &major_ver, &minor_ver, &flags, &api, &reset,
450				 error))
451      return NULL;
452
453   if (reset != __DRI_CTX_RESET_NO_NOTIFICATION)
454      return NULL;
455
456   if (shareList) {
457      pcp_shared = (struct drisw_context *) shareList;
458      shared = pcp_shared->driContext;
459   }
460
461   pcp = Xmalloc(sizeof *pcp);
462   if (pcp == NULL)
463      return NULL;
464
465   memset(pcp, 0, sizeof *pcp);
466   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
467      Xfree(pcp);
468      return NULL;
469   }
470
471   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
472   ctx_attribs[num_ctx_attribs++] = major_ver;
473   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
474   ctx_attribs[num_ctx_attribs++] = minor_ver;
475
476   if (flags != 0) {
477      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
478
479      /* The current __DRI_CTX_FLAG_* values are identical to the
480       * GLX_CONTEXT_*_BIT values.
481       */
482      ctx_attribs[num_ctx_attribs++] = flags;
483   }
484
485   pcp->driContext =
486      (*psc->swrast->createContextAttribs) (psc->driScreen,
487					    api,
488					    config->driConfig,
489					    shared,
490					    num_ctx_attribs / 2,
491					    ctx_attribs,
492					    error,
493					    pcp);
494   if (pcp->driContext == NULL) {
495      Xfree(pcp);
496      return NULL;
497   }
498
499   pcp->base.vtable = &drisw_context_vtable;
500
501   return &pcp->base;
502}
503
504static void
505driswDestroyDrawable(__GLXDRIdrawable * pdraw)
506{
507   struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
508   struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
509
510   (*psc->core->destroyDrawable) (pdp->driDrawable);
511
512   XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
513   Xfree(pdp);
514}
515
516static __GLXDRIdrawable *
517driswCreateDrawable(struct glx_screen *base, XID xDrawable,
518		    GLXDrawable drawable, struct glx_config *modes)
519{
520   struct drisw_drawable *pdp;
521   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
522   struct drisw_screen *psc = (struct drisw_screen *) base;
523   Bool ret;
524   const __DRIswrastExtension *swrast = psc->swrast;
525
526   pdp = Xmalloc(sizeof(*pdp));
527   if (!pdp)
528      return NULL;
529
530   memset(pdp, 0, sizeof *pdp);
531   pdp->base.xDrawable = xDrawable;
532   pdp->base.drawable = drawable;
533   pdp->base.psc = &psc->base;
534
535   ret = XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID);
536   if (!ret) {
537      Xfree(pdp);
538      return NULL;
539   }
540
541   /* Create a new drawable */
542   pdp->driDrawable =
543      (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp);
544
545   if (!pdp->driDrawable) {
546      XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
547      Xfree(pdp);
548      return NULL;
549   }
550
551   pdp->base.destroyDrawable = driswDestroyDrawable;
552
553   return &pdp->base;
554}
555
556static int64_t
557driswSwapBuffers(__GLXDRIdrawable * pdraw,
558                 int64_t target_msc, int64_t divisor, int64_t remainder)
559{
560   struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
561   struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
562
563   (void) target_msc;
564   (void) divisor;
565   (void) remainder;
566
567   (*psc->core->swapBuffers) (pdp->driDrawable);
568
569   return 0;
570}
571
572static void
573driswDestroyScreen(struct glx_screen *base)
574{
575   struct drisw_screen *psc = (struct drisw_screen *) base;
576
577   /* Free the direct rendering per screen data */
578   (*psc->core->destroyScreen) (psc->driScreen);
579   driDestroyConfigs(psc->driver_configs);
580   psc->driScreen = NULL;
581   if (psc->driver)
582      dlclose(psc->driver);
583}
584
585#define SWRAST_DRIVER_NAME "swrast"
586
587static void *
588driOpenSwrast(void)
589{
590   void *driver = NULL;
591
592   if (driver == NULL)
593      driver = driOpenDriver(SWRAST_DRIVER_NAME);
594
595   return driver;
596}
597
598static const struct glx_screen_vtable drisw_screen_vtable = {
599   drisw_create_context,
600   drisw_create_context_attribs
601};
602
603static void
604driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
605{
606   int i;
607
608   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
609
610   if (psc->swrast->base.version >= 3) {
611      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
612      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
613
614      /* DRISW version >= 2 implies support for OpenGL ES 2.0.
615       */
616      __glXEnableDirectExtension(&psc->base,
617				 "GLX_EXT_create_context_es2_profile");
618   }
619
620   /* FIXME: Figure out what other extensions can be ported here from dri2. */
621   for (i = 0; extensions[i]; i++) {
622      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
623	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
624	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
625      }
626   }
627}
628
629static struct glx_screen *
630driswCreateScreen(int screen, struct glx_display *priv)
631{
632   __GLXDRIscreen *psp;
633   const __DRIconfig **driver_configs;
634   const __DRIextension **extensions;
635   struct drisw_screen *psc;
636   struct glx_config *configs = NULL, *visuals = NULL;
637   int i;
638
639   psc = Xcalloc(1, sizeof *psc);
640   if (psc == NULL)
641      return NULL;
642
643   memset(psc, 0, sizeof *psc);
644   if (!glx_screen_init(&psc->base, screen, priv)) {
645      Xfree(psc);
646      return NULL;
647   }
648
649   psc->driver = driOpenSwrast();
650   if (psc->driver == NULL)
651      goto handle_error;
652
653   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
654   if (extensions == NULL) {
655      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
656      goto handle_error;
657   }
658
659   for (i = 0; extensions[i]; i++) {
660      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
661	 psc->core = (__DRIcoreExtension *) extensions[i];
662      if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
663	 psc->swrast = (__DRIswrastExtension *) extensions[i];
664   }
665
666   if (psc->core == NULL || psc->swrast == NULL) {
667      ErrorMessageF("core dri extension not found\n");
668      goto handle_error;
669   }
670
671   psc->driScreen =
672      psc->swrast->createNewScreen(screen, loader_extensions,
673				   &driver_configs, psc);
674   if (psc->driScreen == NULL) {
675      ErrorMessageF("failed to create dri screen\n");
676      goto handle_error;
677   }
678
679   extensions = psc->core->getExtensions(psc->driScreen);
680   driswBindExtensions(psc, extensions);
681
682   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
683   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
684
685   if (!configs || !visuals)
686       goto handle_error;
687
688   glx_config_destroy_list(psc->base.configs);
689   psc->base.configs = configs;
690   glx_config_destroy_list(psc->base.visuals);
691   psc->base.visuals = visuals;
692
693   psc->driver_configs = driver_configs;
694
695   psc->base.vtable = &drisw_screen_vtable;
696   psp = &psc->vtable;
697   psc->base.driScreen = psp;
698   psp->destroyScreen = driswDestroyScreen;
699   psp->createDrawable = driswCreateDrawable;
700   psp->swapBuffers = driswSwapBuffers;
701
702   return &psc->base;
703
704 handle_error:
705   if (configs)
706       glx_config_destroy_list(configs);
707   if (visuals)
708       glx_config_destroy_list(visuals);
709   if (psc->driScreen)
710       psc->core->destroyScreen(psc->driScreen);
711   psc->driScreen = NULL;
712
713   if (psc->driver)
714      dlclose(psc->driver);
715   glx_screen_cleanup(&psc->base);
716   Xfree(psc);
717
718   CriticalErrorMessageF("failed to load driver: %s\n", SWRAST_DRIVER_NAME);
719
720   return NULL;
721}
722
723/* Called from __glXFreeDisplayPrivate.
724 */
725static void
726driswDestroyDisplay(__GLXDRIdisplay * dpy)
727{
728   Xfree(dpy);
729}
730
731/*
732 * Allocate, initialize and return a __DRIdisplayPrivate object.
733 * This is called from __glXInitialize() when we are given a new
734 * display pointer.
735 */
736_X_HIDDEN __GLXDRIdisplay *
737driswCreateDisplay(Display * dpy)
738{
739   struct drisw_display *pdpyp;
740
741   pdpyp = Xmalloc(sizeof *pdpyp);
742   if (pdpyp == NULL)
743      return NULL;
744
745   pdpyp->base.destroyDisplay = driswDestroyDisplay;
746   pdpyp->base.createScreen = driswCreateScreen;
747
748   return &pdpyp->base;
749}
750
751#endif /* GLX_DIRECT_RENDERING */
752