853940bb679437956e015558dbe4afe0aa4b20c3
[mesa.git] / src / glx / x11 / dri_glx.c
1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
32 *
33 */
34
35 #ifdef GLX_DIRECT_RENDERING
36
37 #include <unistd.h>
38 #include <X11/Xlibint.h>
39 #include <X11/extensions/Xext.h>
40 #include <X11/extensions/extutil.h>
41 #include "glheader.h"
42 #include "glxclient.h"
43 #include "xf86dri.h"
44 #include "sarea.h"
45 #include <stdio.h>
46 #include <dlfcn.h>
47 #include <sys/types.h>
48 #include <stdarg.h>
49 #include "glcontextmodes.h"
50 #include <sys/mman.h>
51 #include "xf86drm.h"
52
53
54 #ifndef RTLD_NOW
55 #define RTLD_NOW 0
56 #endif
57 #ifndef RTLD_GLOBAL
58 #define RTLD_GLOBAL 0
59 #endif
60
61 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
62 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
63
64 struct __GLXDRIdisplayPrivateRec {
65 __GLXDRIdisplay base;
66
67 /*
68 ** XFree86-DRI version information
69 */
70 int driMajor;
71 int driMinor;
72 int driPatch;
73 };
74
75 struct __GLXDRIcontextPrivateRec {
76 __GLXDRIcontext base;
77 __DRIcontext driContext;
78 XID hwContextID;
79 };
80
81 #ifndef DEFAULT_DRIVER_DIR
82 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
83 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
84 #endif
85
86 static void InfoMessageF(const char *f, ...)
87 {
88 va_list args;
89 const char *env;
90
91 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
92 fprintf(stderr, "libGL: ");
93 va_start(args, f);
94 vfprintf(stderr, f, args);
95 va_end(args);
96 }
97 }
98
99 /**
100 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
101 */
102 static void ErrorMessageF(const char *f, ...)
103 {
104 va_list args;
105 const char *env;
106
107 if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
108 fprintf(stderr, "libGL error: ");
109 va_start(args, f);
110 vfprintf(stderr, f, args);
111 va_end(args);
112 }
113 }
114
115
116 /**
117 * Versioned name of the expected \c __driCreateNewScreen function.
118 *
119 * The version of the last incompatible loader/driver inteface change is
120 * appended to the name of the \c __driCreateNewScreen function. This
121 * prevents loaders from trying to load drivers that are too old.
122 */
123 static const char createNewScreenName[] = __DRI_CREATE_NEW_SCREEN_STRING;
124
125
126 /**
127 * Try to \c dlopen the named driver.
128 *
129 * This function adds the "_dri.so" suffix to the driver name and searches the
130 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
131 * order to find the driver.
132 *
133 * \param driverName - a name like "tdfx", "i810", "mga", etc.
134 *
135 * \returns
136 * A handle from \c dlopen, or \c NULL if driver file not found.
137 */
138 static void *OpenDriver(const char *driverName)
139 {
140 void *glhandle, *handle;
141 const char *libPaths, *p, *next;
142 char realDriverName[200];
143 int len;
144
145 /* Attempt to make sure libGL symbols will be visible to the driver */
146 glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
147
148 libPaths = DEFAULT_DRIVER_DIR;
149 if (geteuid() == getuid()) {
150 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
151 libPaths = getenv("LIBGL_DRIVERS_PATH");
152 if (!libPaths)
153 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
154 }
155
156 handle = NULL;
157 for (p = libPaths; *p; p = next) {
158 next = strchr(p, ':');
159 if (next == NULL) {
160 len = strlen(p);
161 next = p + len;
162 } else {
163 len = next - p;
164 next++;
165 }
166
167 #ifdef GLX_USE_TLS
168 snprintf(realDriverName, sizeof realDriverName,
169 "%.*s/tls/%s_dri.so", len, p, driverName);
170 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
171 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
172 #endif
173
174 if ( handle == NULL ) {
175 snprintf(realDriverName, sizeof realDriverName,
176 "%.*s/%s_dri.so", len, p, driverName);
177 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
178 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
179 }
180
181 if ( handle != NULL )
182 break;
183 else
184 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
185 }
186
187 if (!handle)
188 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
189
190 if (glhandle)
191 dlclose(glhandle);
192
193 return handle;
194 }
195
196
197 /*
198 * Given a display pointer and screen number, determine the name of
199 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
200 * Return True for success, False for failure.
201 */
202 static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
203 {
204 int directCapable;
205 Bool b;
206 int driverMajor, driverMinor, driverPatch;
207
208 *driverName = NULL;
209
210 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
211 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
212 return False;
213 }
214 if (!directCapable) {
215 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
216 return False;
217 }
218
219 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
220 &driverPatch, driverName);
221 if (!b) {
222 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum);
223 return False;
224 }
225
226 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
227 driverMajor, driverMinor, driverPatch, *driverName, scrNum);
228
229 return True;
230 }
231
232
233 /*
234 * Given a display pointer and screen number, return a __DRIdriver handle.
235 * Return NULL if anything goes wrong.
236 */
237 static void *driGetDriver(Display *dpy, int scrNum)
238 {
239 char *driverName;
240 void *ret;
241
242 if (GetDriverName(dpy, scrNum, &driverName)) {
243 ret = OpenDriver(driverName);
244 if (driverName)
245 Xfree(driverName);
246 return ret;
247 }
248 return NULL;
249 }
250
251 /*
252 * Exported function for querying the DRI driver for a given screen.
253 *
254 * The returned char pointer points to a static array that will be
255 * overwritten by subsequent calls.
256 */
257 PUBLIC const char *glXGetScreenDriver (Display *dpy, int scrNum) {
258 static char ret[32];
259 char *driverName;
260 if (GetDriverName(dpy, scrNum, &driverName)) {
261 int len;
262 if (!driverName)
263 return NULL;
264 len = strlen (driverName);
265 if (len >= 31)
266 return NULL;
267 memcpy (ret, driverName, len+1);
268 Xfree(driverName);
269 return ret;
270 }
271 return NULL;
272 }
273
274
275 /*
276 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
277 *
278 * The returned char pointer points directly into the driver. Therefore
279 * it should be treated as a constant.
280 *
281 * If the driver was not found or does not support configuration NULL is
282 * returned.
283 *
284 * Note: The driver remains opened after this function returns.
285 */
286 PUBLIC const char *glXGetDriverConfig (const char *driverName) {
287 void *handle = OpenDriver (driverName);
288 if (handle)
289 return dlsym (handle, "__driConfigOptions");
290 else
291 return NULL;
292 }
293
294 static void
295 filter_modes( __GLcontextModes ** server_modes,
296 const __GLcontextModes * driver_modes )
297 {
298 __GLcontextModes * m;
299 __GLcontextModes ** prev_next;
300 const __GLcontextModes * check;
301
302 if (driver_modes == NULL) {
303 fprintf(stderr, "libGL warning: 3D driver returned no fbconfigs.\n");
304 return;
305 }
306
307 /* For each mode in server_modes, check to see if a matching mode exists
308 * in driver_modes. If not, then the mode is not available.
309 */
310
311 prev_next = server_modes;
312 for ( m = *prev_next ; m != NULL ; m = *prev_next ) {
313 GLboolean do_delete = GL_TRUE;
314
315 for ( check = driver_modes ; check != NULL ; check = check->next ) {
316 if ( _gl_context_modes_are_same( m, check ) ) {
317 do_delete = GL_FALSE;
318 break;
319 }
320 }
321
322 /* The 3D has to support all the modes that match the GLX visuals
323 * sent from the X server.
324 */
325 if ( do_delete && (m->visualID != 0) ) {
326 do_delete = GL_FALSE;
327
328 /* don't warn for this visual (Novell #247471 / X.Org #6689) */
329 if (m->visualRating != GLX_NON_CONFORMANT_CONFIG) {
330 fprintf(stderr, "libGL warning: 3D driver claims to not "
331 "support visual 0x%02x\n", m->visualID);
332 }
333 }
334
335 if ( do_delete ) {
336 *prev_next = m->next;
337
338 m->next = NULL;
339 _gl_context_modes_destroy( m );
340 }
341 else {
342 prev_next = & m->next;
343 }
344 }
345 }
346
347 #ifdef XDAMAGE_1_1_INTERFACE
348 static GLboolean has_damage_post(Display *dpy)
349 {
350 static GLboolean inited = GL_FALSE;
351 static GLboolean has_damage;
352
353 if (!inited) {
354 int major, minor;
355
356 if (XDamageQueryVersion(dpy, &major, &minor) &&
357 major == 1 && minor >= 1)
358 {
359 has_damage = GL_TRUE;
360 } else {
361 has_damage = GL_FALSE;
362 }
363 inited = GL_TRUE;
364 }
365
366 return has_damage;
367 }
368 #endif /* XDAMAGE_1_1_INTERFACE */
369
370 static void __glXReportDamage(__DRIdrawable *driDraw,
371 int x, int y,
372 drm_clip_rect_t *rects, int num_rects,
373 GLboolean front_buffer)
374 {
375 #ifdef XDAMAGE_1_1_INTERFACE
376 XRectangle *xrects;
377 XserverRegion region;
378 int i;
379 int x_off, y_off;
380 __GLXdrawable *glxDraw =
381 containerOf(driDraw, __GLXdrawable, driDrawable);
382 __GLXscreenConfigs *psc = glxDraw->psc;
383 Display *dpy = psc->dpy;
384 Drawable drawable;
385
386 if (!has_damage_post(dpy))
387 return;
388
389 if (front_buffer) {
390 x_off = x;
391 y_off = y;
392 drawable = RootWindow(dpy, psc->scr);
393 } else{
394 x_off = 0;
395 y_off = 0;
396 drawable = glxDraw->drawable;
397 }
398
399 xrects = malloc(sizeof(XRectangle) * num_rects);
400 if (xrects == NULL)
401 return;
402
403 for (i = 0; i < num_rects; i++) {
404 xrects[i].x = rects[i].x1 + x_off;
405 xrects[i].y = rects[i].y1 + y_off;
406 xrects[i].width = rects[i].x2 - rects[i].x1;
407 xrects[i].height = rects[i].y2 - rects[i].y1;
408 }
409 region = XFixesCreateRegion(dpy, xrects, num_rects);
410 free(xrects);
411 XDamageAdd(dpy, drawable, region);
412 XFixesDestroyRegion(dpy, region);
413 #endif
414 }
415
416 static GLboolean
417 __glXDRIGetDrawableInfo(__DRIdrawable *drawable,
418 unsigned int *index, unsigned int *stamp,
419 int *X, int *Y, int *W, int *H,
420 int *numClipRects, drm_clip_rect_t ** pClipRects,
421 int *backX, int *backY,
422 int *numBackClipRects, drm_clip_rect_t **pBackClipRects)
423 {
424 __GLXDRIdrawable *glxDraw =
425 containerOf(drawable, __GLXDRIdrawable, driDrawable);
426 __GLXscreenConfigs *psc = glxDraw->psc;
427 Display *dpy = psc->dpy;
428
429 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
430 index, stamp, X, Y, W, H,
431 numClipRects, pClipRects,
432 backX, backY,
433 numBackClipRects, pBackClipRects);
434 }
435
436
437 /**
438 * Table of functions exported by the loader to the driver.
439 */
440 static const __DRIcontextModesExtension contextModesExtension = {
441 { __DRI_CONTEXT_MODES, __DRI_CONTEXT_MODES_VERSION },
442 _gl_context_modes_create,
443 _gl_context_modes_destroy,
444 };
445
446 static const __DRIsystemTimeExtension systemTimeExtension = {
447 { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
448 __glXGetUST,
449 __driGetMscRateOML,
450 };
451
452 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
453 { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
454 __glXDRIGetDrawableInfo
455 };
456
457 static const __DRIdamageExtension damageExtension = {
458 { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
459 __glXReportDamage,
460 };
461
462 static const __DRIextension *loader_extensions[] = {
463 &contextModesExtension.base,
464 &systemTimeExtension.base,
465 &getDrawableInfoExtension.base,
466 &damageExtension.base,
467 NULL
468 };
469
470
471 /**
472 * Perform the required libGL-side initialization and call the client-side
473 * driver's \c __driCreateNewScreen function.
474 *
475 * \param dpy Display pointer.
476 * \param scrn Screen number on the display.
477 * \param psc DRI screen information.
478 * \param driDpy DRI display information.
479 * \param createNewScreen Pointer to the client-side driver's
480 * \c __driCreateNewScreen function.
481 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
482 * the client-side driver on success, or \c NULL on failure.
483 *
484 * \todo This function needs to be modified to remove context-modes from the
485 * list stored in the \c __GLXscreenConfigsRec to match the list
486 * returned by the client-side driver.
487 */
488 static void *
489 CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
490 __GLXDRIdisplayPrivate * driDpy,
491 PFNCREATENEWSCREENFUNC createNewScreen)
492 {
493 void *psp = NULL;
494 #ifndef GLX_USE_APPLEGL
495 drm_handle_t hSAREA;
496 drmAddress pSAREA = MAP_FAILED;
497 char *BusID;
498 __DRIversion ddx_version;
499 __DRIversion dri_version;
500 __DRIversion drm_version;
501 __DRIframebuffer framebuffer;
502 int fd = -1;
503 int status;
504 const char * err_msg;
505 const char * err_extra;
506
507 dri_version.major = driDpy->driMajor;
508 dri_version.minor = driDpy->driMinor;
509 dri_version.patch = driDpy->driPatch;
510
511
512 err_msg = "XF86DRIOpenConnection";
513 err_extra = NULL;
514
515 framebuffer.base = MAP_FAILED;
516 framebuffer.dev_priv = NULL;
517
518 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
519 int newlyopened;
520 fd = drmOpenOnce(NULL,BusID, &newlyopened);
521 Xfree(BusID); /* No longer needed */
522
523 err_msg = "open DRM";
524 err_extra = strerror( -fd );
525
526 if (fd >= 0) {
527 drm_magic_t magic;
528
529 err_msg = "drmGetMagic";
530 err_extra = NULL;
531
532 if (!drmGetMagic(fd, &magic)) {
533 drmVersionPtr version = drmGetVersion(fd);
534 if (version) {
535 drm_version.major = version->version_major;
536 drm_version.minor = version->version_minor;
537 drm_version.patch = version->version_patchlevel;
538 drmFreeVersion(version);
539 }
540 else {
541 drm_version.major = -1;
542 drm_version.minor = -1;
543 drm_version.patch = -1;
544 }
545
546 err_msg = "XF86DRIAuthConnection";
547 if (!newlyopened || XF86DRIAuthConnection(dpy, scrn, magic)) {
548 char *driverName;
549
550 /*
551 * Get device name (like "tdfx") and the ddx version
552 * numbers. We'll check the version in each DRI driver's
553 * "createNewScreen" function.
554 */
555 err_msg = "XF86DRIGetClientDriverName";
556 if (XF86DRIGetClientDriverName(dpy, scrn,
557 &ddx_version.major,
558 &ddx_version.minor,
559 &ddx_version.patch,
560 &driverName)) {
561 drm_handle_t hFB;
562 int junk;
563
564 /* No longer needed. */
565 Xfree( driverName );
566
567
568 /*
569 * Get device-specific info. pDevPriv will point to a struct
570 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
571 * that has information about the screen size, depth, pitch,
572 * ancilliary buffers, DRM mmap handles, etc.
573 */
574 err_msg = "XF86DRIGetDeviceInfo";
575 if (XF86DRIGetDeviceInfo(dpy, scrn,
576 &hFB,
577 &junk,
578 &framebuffer.size,
579 &framebuffer.stride,
580 &framebuffer.dev_priv_size,
581 &framebuffer.dev_priv)) {
582 framebuffer.width = DisplayWidth(dpy, scrn);
583 framebuffer.height = DisplayHeight(dpy, scrn);
584
585 /*
586 * Map the framebuffer region.
587 */
588 status = drmMap(fd, hFB, framebuffer.size,
589 (drmAddressPtr)&framebuffer.base);
590
591 err_msg = "drmMap of framebuffer";
592 err_extra = strerror( -status );
593
594 if ( status == 0 ) {
595 /*
596 * Map the SAREA region. Further mmap regions
597 * may be setup in each DRI driver's
598 * "createNewScreen" function.
599 */
600 status = drmMap(fd, hSAREA, SAREA_MAX,
601 &pSAREA);
602
603 err_msg = "drmMap of sarea";
604 err_extra = strerror( -status );
605
606 if ( status == 0 ) {
607 __GLcontextModes * driver_modes = NULL;
608
609 err_msg = "InitDriver";
610 err_extra = NULL;
611 psp = (*createNewScreen)(scrn,
612 &psc->__driScreen,
613 & ddx_version,
614 & dri_version,
615 & drm_version,
616 & framebuffer,
617 pSAREA,
618 fd,
619 loader_extensions,
620 & driver_modes );
621
622 filter_modes(&psc->configs, driver_modes);
623 filter_modes(&psc->visuals, driver_modes);
624 _gl_context_modes_destroy(driver_modes);
625 }
626 }
627 }
628 }
629 }
630 }
631 }
632 }
633
634 if ( psp == NULL ) {
635 if ( pSAREA != MAP_FAILED ) {
636 (void)drmUnmap(pSAREA, SAREA_MAX);
637 }
638
639 if ( framebuffer.base != MAP_FAILED ) {
640 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
641 }
642
643 if ( framebuffer.dev_priv != NULL ) {
644 Xfree(framebuffer.dev_priv);
645 }
646
647 if ( fd >= 0 ) {
648 (void)drmCloseOnce(fd);
649 }
650
651 (void)XF86DRICloseConnection(dpy, scrn);
652
653 if ( err_extra != NULL ) {
654 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
655 err_extra);
656 }
657 else {
658 fprintf(stderr, "libGL error: %s failed\n", err_msg );
659 }
660
661 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
662 }
663 #endif /* !GLX_USE_APPLEGL */
664
665 return psp;
666 }
667
668 static void driDestroyContext(__GLXDRIcontext *context,
669 __GLXscreenConfigs *psc, Display *dpy)
670 {
671 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
672
673 (*pcp->driContext.destroyContext)(&pcp->driContext);
674
675 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
676 }
677
678 static Bool driBindContext(__GLXDRIcontext *context,
679 __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
680 {
681 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
682
683 return (*pcp->driContext.bindContext)(&pcp->driContext,
684 &draw->driDrawable,
685 &read->driDrawable);
686 }
687
688 static void driUnbindContext(__GLXDRIcontext *context)
689 {
690 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
691
692 (*pcp->driContext.unbindContext)(&pcp->driContext);
693 }
694
695 static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
696 const __GLcontextModes *mode,
697 GLXContext gc,
698 GLXContext shareList, int renderType)
699 {
700 __GLXDRIcontextPrivate *pcp, *pcp_shared;
701 drm_context_t hwContext;
702 __DRIcontext *shared = NULL;
703
704 if (psc && psc->driScreen) {
705 if (shareList) {
706 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
707 shared = &pcp_shared->driContext;
708 }
709
710 pcp = Xmalloc(sizeof *pcp);
711 if (pcp == NULL)
712 return NULL;
713
714 if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
715 mode->visualID,
716 &pcp->hwContextID, &hwContext)) {
717 Xfree(pcp);
718 return NULL;
719 }
720
721 pcp->driContext.private =
722 (*psc->__driScreen.createNewContext)(&psc->__driScreen,
723 mode, renderType,
724 shared,
725 hwContext,
726 &pcp->driContext);
727 if (pcp->driContext.private == NULL) {
728 XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
729 Xfree(pcp);
730 return NULL;
731 }
732
733 pcp->base.destroyContext = driDestroyContext;
734 pcp->base.bindContext = driBindContext;
735 pcp->base.unbindContext = driUnbindContext;
736
737 return &pcp->base;
738 }
739
740 return NULL;
741 }
742
743
744 static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
745 GLXDrawable drawable,
746 GLXContext gc)
747 {
748 __GLXDRIdrawable *pdraw;
749 drm_drawable_t hwDrawable;
750 void *empty_attribute_list = NULL;
751
752 pdraw = Xmalloc(sizeof(*pdraw));
753 if (!pdraw)
754 return NULL;
755
756 pdraw->drawable = drawable;
757 pdraw->psc = psc;
758
759 if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
760 return NULL;
761
762 /* Create a new drawable */
763 pdraw->driDrawable.private =
764 (*psc->__driScreen.createNewDrawable)(&psc->__driScreen,
765 gc->mode,
766 &pdraw->driDrawable,
767 hwDrawable,
768 GLX_WINDOW_BIT,
769 empty_attribute_list);
770
771 if (!pdraw->driDrawable.private) {
772 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
773 Xfree(pdraw);
774 return NULL;
775 }
776
777 if (__glxHashInsert(psc->drawHash, drawable, pdraw)) {
778 (*pdraw->driDrawable.destroyDrawable)(&pdraw->driDrawable);
779 XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
780 Xfree(pdraw);
781 return NULL;
782 }
783
784 return pdraw;
785 }
786
787 static void driDestroyScreen(__GLXscreenConfigs *psc)
788 {
789 /* Free the direct rendering per screen data */
790 if (psc->__driScreen.private)
791 (*psc->__driScreen.destroyScreen)(&psc->__driScreen);
792 psc->__driScreen.private = NULL;
793 if (psc->drawHash)
794 __glxHashDestroy(psc->drawHash);
795 if (psc->driver)
796 dlclose(psc->driver);
797 }
798
799 static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
800 __GLXdisplayPrivate *priv)
801 {
802 PFNCREATENEWSCREENFUNC createNewScreen;
803 __GLXDRIdisplayPrivate *pdp;
804 __GLXDRIscreen *psp;
805
806 psp = Xmalloc(sizeof *psp);
807 if (psp == NULL)
808 return NULL;
809
810 /* Create drawable hash */
811 psc->drawHash = __glxHashCreate();
812 if ( psc->drawHash == NULL )
813 return NULL;
814
815 /* Initialize per screen dynamic client GLX extensions */
816 psc->ext_list_first_time = GL_TRUE;
817
818 psc->driver = driGetDriver(priv->dpy, screen);
819 createNewScreen = dlsym(psc->driver, createNewScreenName);
820 if (createNewScreenName == NULL)
821 return NULL;
822
823 pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
824 psc->__driScreen.private =
825 CallCreateNewScreen(psc->dpy, screen, psc, pdp, createNewScreen);
826 if (psc->__driScreen.private != NULL)
827 __glXScrEnableDRIExtension(psc);
828
829 psp->destroyScreen = driDestroyScreen;
830 psp->createContext = driCreateContext;
831 psp->createDrawable = driCreateDrawable;
832
833 return psp;
834 }
835
836 /* Called from __glXFreeDisplayPrivate.
837 */
838 static void driDestroyDisplay(__GLXDRIdisplay *dpy)
839 {
840 Xfree(dpy);
841 }
842
843 /*
844 * Allocate, initialize and return a __DRIdisplayPrivate object.
845 * This is called from __glXInitialize() when we are given a new
846 * display pointer.
847 */
848 __GLXDRIdisplay *driCreateDisplay(Display *dpy)
849 {
850 __GLXDRIdisplayPrivate *pdpyp;
851 int eventBase, errorBase;
852 int major, minor, patch;
853
854 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
855 return NULL;
856 }
857
858 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
859 return NULL;
860 }
861
862 pdpyp = Xmalloc(sizeof *pdpyp);
863 if (!pdpyp) {
864 return NULL;
865 }
866
867 pdpyp->driMajor = major;
868 pdpyp->driMinor = minor;
869 pdpyp->driPatch = patch;
870
871 pdpyp->base.destroyDisplay = driDestroyDisplay;
872 pdpyp->base.createScreen = driCreateScreen;
873
874 return &pdpyp->base;
875 }
876
877 #endif /* GLX_DIRECT_RENDERING */