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