drisw_glx.c revision 2c778375a1356ffb8db1522bc3fc64c568c35cb1
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   uint32_t ctx_attribs[2 * 4];
437   unsigned num_ctx_attribs = 0;
438
439   if (!psc->base.driScreen)
440      return NULL;
441
442   if (psc->swrast->base.version < 3)
443      return NULL;
444
445   /* Remap the GLX tokens to DRI2 tokens.
446    */
447   if (!dri2_convert_glx_attribs(num_attribs, attribs,
448				 &major_ver, &minor_ver, &flags, &api,
449				 error))
450      return NULL;
451
452   if (shareList) {
453      pcp_shared = (struct drisw_context *) shareList;
454      shared = pcp_shared->driContext;
455   }
456
457   pcp = Xmalloc(sizeof *pcp);
458   if (pcp == NULL)
459      return NULL;
460
461   memset(pcp, 0, sizeof *pcp);
462   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
463      Xfree(pcp);
464      return NULL;
465   }
466
467   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
468   ctx_attribs[num_ctx_attribs++] = major_ver;
469   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
470   ctx_attribs[num_ctx_attribs++] = minor_ver;
471
472   if (flags != 0) {
473      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
474
475      /* The current __DRI_CTX_FLAG_* values are identical to the
476       * GLX_CONTEXT_*_BIT values.
477       */
478      ctx_attribs[num_ctx_attribs++] = flags;
479   }
480
481   pcp->driContext =
482      (*psc->swrast->createContextAttribs) (psc->driScreen,
483					    api,
484					    config->driConfig,
485					    shared,
486					    num_ctx_attribs / 2,
487					    ctx_attribs,
488					    error,
489					    pcp);
490   if (pcp->driContext == NULL) {
491      Xfree(pcp);
492      return NULL;
493   }
494
495   pcp->base.vtable = &drisw_context_vtable;
496
497   return &pcp->base;
498}
499
500static void
501driswDestroyDrawable(__GLXDRIdrawable * pdraw)
502{
503   struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
504   struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
505
506   (*psc->core->destroyDrawable) (pdp->driDrawable);
507
508   XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
509   Xfree(pdp);
510}
511
512static __GLXDRIdrawable *
513driswCreateDrawable(struct glx_screen *base, XID xDrawable,
514		    GLXDrawable drawable, struct glx_config *modes)
515{
516   struct drisw_drawable *pdp;
517   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
518   struct drisw_screen *psc = (struct drisw_screen *) base;
519   Bool ret;
520   const __DRIswrastExtension *swrast = psc->swrast;
521
522   pdp = Xmalloc(sizeof(*pdp));
523   if (!pdp)
524      return NULL;
525
526   memset(pdp, 0, sizeof *pdp);
527   pdp->base.xDrawable = xDrawable;
528   pdp->base.drawable = drawable;
529   pdp->base.psc = &psc->base;
530
531   ret = XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID);
532   if (!ret) {
533      Xfree(pdp);
534      return NULL;
535   }
536
537   /* Create a new drawable */
538   pdp->driDrawable =
539      (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp);
540
541   if (!pdp->driDrawable) {
542      XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
543      Xfree(pdp);
544      return NULL;
545   }
546
547   pdp->base.destroyDrawable = driswDestroyDrawable;
548
549   return &pdp->base;
550}
551
552static int64_t
553driswSwapBuffers(__GLXDRIdrawable * pdraw,
554                 int64_t target_msc, int64_t divisor, int64_t remainder)
555{
556   struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
557   struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
558
559   (void) target_msc;
560   (void) divisor;
561   (void) remainder;
562
563   (*psc->core->swapBuffers) (pdp->driDrawable);
564
565   return 0;
566}
567
568static void
569driswDestroyScreen(struct glx_screen *base)
570{
571   struct drisw_screen *psc = (struct drisw_screen *) base;
572
573   /* Free the direct rendering per screen data */
574   (*psc->core->destroyScreen) (psc->driScreen);
575   driDestroyConfigs(psc->driver_configs);
576   psc->driScreen = NULL;
577   if (psc->driver)
578      dlclose(psc->driver);
579}
580
581#define SWRAST_DRIVER_NAME "swrast"
582
583static void *
584driOpenSwrast(void)
585{
586   void *driver = NULL;
587
588   if (driver == NULL)
589      driver = driOpenDriver(SWRAST_DRIVER_NAME);
590
591   return driver;
592}
593
594static const struct glx_screen_vtable drisw_screen_vtable = {
595   drisw_create_context,
596   drisw_create_context_attribs
597};
598
599static void
600driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
601{
602   int i;
603
604   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
605
606   if (psc->swrast->base.version >= 3) {
607      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
608      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
609
610      /* DRISW version >= 2 implies support for OpenGL ES 2.0.
611       */
612      __glXEnableDirectExtension(&psc->base,
613				 "GLX_EXT_create_context_es2_profile");
614   }
615
616   /* FIXME: Figure out what other extensions can be ported here from dri2. */
617   for (i = 0; extensions[i]; i++) {
618      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
619	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
620	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
621      }
622   }
623}
624
625static struct glx_screen *
626driswCreateScreen(int screen, struct glx_display *priv)
627{
628   __GLXDRIscreen *psp;
629   const __DRIconfig **driver_configs;
630   const __DRIextension **extensions;
631   struct drisw_screen *psc;
632   struct glx_config *configs = NULL, *visuals = NULL;
633   int i;
634
635   psc = Xcalloc(1, sizeof *psc);
636   if (psc == NULL)
637      return NULL;
638
639   memset(psc, 0, sizeof *psc);
640   if (!glx_screen_init(&psc->base, screen, priv)) {
641      Xfree(psc);
642      return NULL;
643   }
644
645   psc->driver = driOpenSwrast();
646   if (psc->driver == NULL)
647      goto handle_error;
648
649   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
650   if (extensions == NULL) {
651      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
652      goto handle_error;
653   }
654
655   for (i = 0; extensions[i]; i++) {
656      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
657	 psc->core = (__DRIcoreExtension *) extensions[i];
658      if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
659	 psc->swrast = (__DRIswrastExtension *) extensions[i];
660   }
661
662   if (psc->core == NULL || psc->swrast == NULL) {
663      ErrorMessageF("core dri extension not found\n");
664      goto handle_error;
665   }
666
667   psc->driScreen =
668      psc->swrast->createNewScreen(screen, loader_extensions,
669				   &driver_configs, psc);
670   if (psc->driScreen == NULL) {
671      ErrorMessageF("failed to create dri screen\n");
672      goto handle_error;
673   }
674
675   extensions = psc->core->getExtensions(psc->driScreen);
676   driswBindExtensions(psc, extensions);
677
678   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
679   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
680
681   if (!configs || !visuals)
682       goto handle_error;
683
684   glx_config_destroy_list(psc->base.configs);
685   psc->base.configs = configs;
686   glx_config_destroy_list(psc->base.visuals);
687   psc->base.visuals = visuals;
688
689   psc->driver_configs = driver_configs;
690
691   psc->base.vtable = &drisw_screen_vtable;
692   psp = &psc->vtable;
693   psc->base.driScreen = psp;
694   psp->destroyScreen = driswDestroyScreen;
695   psp->createDrawable = driswCreateDrawable;
696   psp->swapBuffers = driswSwapBuffers;
697
698   return &psc->base;
699
700 handle_error:
701   if (configs)
702       glx_config_destroy_list(configs);
703   if (visuals)
704       glx_config_destroy_list(visuals);
705   if (psc->driScreen)
706       psc->core->destroyScreen(psc->driScreen);
707   psc->driScreen = NULL;
708
709   if (psc->driver)
710      dlclose(psc->driver);
711   glx_screen_cleanup(&psc->base);
712   Xfree(psc);
713
714   CriticalErrorMessageF("failed to load driver: %s\n", SWRAST_DRIVER_NAME);
715
716   return NULL;
717}
718
719/* Called from __glXFreeDisplayPrivate.
720 */
721static void
722driswDestroyDisplay(__GLXDRIdisplay * dpy)
723{
724   Xfree(dpy);
725}
726
727/*
728 * Allocate, initialize and return a __DRIdisplayPrivate object.
729 * This is called from __glXInitialize() when we are given a new
730 * display pointer.
731 */
732_X_HIDDEN __GLXDRIdisplay *
733driswCreateDisplay(Display * dpy)
734{
735   struct drisw_display *pdpyp;
736
737   pdpyp = Xmalloc(sizeof *pdpyp);
738   if (pdpyp == NULL)
739      return NULL;
740
741   pdpyp->base.destroyDisplay = driswDestroyDisplay;
742   pdpyp->base.createScreen = driswCreateScreen;
743
744   return &pdpyp->base;
745}
746
747#endif /* GLX_DIRECT_RENDERING */
748