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