1 /**************************************************************************
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
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:
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
35 #ifdef GLX_DIRECT_RENDERING
38 #include <X11/Xlibint.h>
39 #include <X11/extensions/Xext.h>
40 #include <X11/extensions/extutil.h>
42 #include "glxclient.h"
47 #include <sys/types.h>
49 #include "glcontextmodes.h"
61 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate
;
62 struct __GLXDRIdisplayPrivateRec
{
66 ** XFree86-DRI version information
73 #ifndef DEFAULT_DRIVER_DIR
74 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
75 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
78 static void InfoMessageF(const char *f
, ...)
83 if ((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) {
84 fprintf(stderr
, "libGL: ");
86 vfprintf(stderr
, f
, args
);
92 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
94 static void ErrorMessageF(const char *f
, ...)
99 if ((env
= getenv("LIBGL_DEBUG")) && !strstr(env
, "quiet")) {
100 fprintf(stderr
, "libGL error: ");
102 vfprintf(stderr
, f
, args
);
109 * Versioned name of the expected \c __driCreateNewScreen function.
111 * The version of the last incompatible loader/driver inteface change is
112 * appended to the name of the \c __driCreateNewScreen function. This
113 * prevents loaders from trying to load drivers that are too old.
115 static const char createNewScreenName
[] = __DRI_CREATE_NEW_SCREEN_STRING
;
119 * Try to \c dlopen the named driver.
121 * This function adds the "_dri.so" suffix to the driver name and searches the
122 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
123 * order to find the driver.
125 * \param driverName - a name like "tdfx", "i810", "mga", etc.
128 * A handle from \c dlopen, or \c NULL if driver file not found.
130 static void *OpenDriver(const char *driverName
)
132 void *glhandle
, *handle
;
133 const char *libPaths
, *p
, *next
;
134 char realDriverName
[200];
137 /* Attempt to make sure libGL symbols will be visible to the driver */
138 glhandle
= dlopen("libGL.so.1", RTLD_NOW
| RTLD_GLOBAL
);
140 libPaths
= DEFAULT_DRIVER_DIR
;
141 if (geteuid() == getuid()) {
142 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
143 libPaths
= getenv("LIBGL_DRIVERS_PATH");
145 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
149 for (p
= libPaths
; *p
; p
= next
) {
150 next
= strchr(p
, ':');
160 snprintf(realDriverName
, sizeof realDriverName
,
161 "%.*s/tls/%s_dri.so", len
, p
, driverName
);
162 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
163 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
166 if ( handle
== NULL
) {
167 snprintf(realDriverName
, sizeof realDriverName
,
168 "%.*s/%s_dri.so", len
, p
, driverName
);
169 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
170 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
173 if ( handle
!= NULL
)
176 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
180 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
190 * Given a display pointer and screen number, determine the name of
191 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
192 * Return True for success, False for failure.
194 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
198 int driverMajor
, driverMinor
, driverPatch
;
202 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
203 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
206 if (!directCapable
) {
207 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
211 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
212 &driverPatch
, driverName
);
214 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
218 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
219 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
226 * Given a display pointer and screen number, return a __DRIdriver handle.
227 * Return NULL if anything goes wrong.
229 static void *driGetDriver(Display
*dpy
, int scrNum
)
234 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
235 ret
= OpenDriver(driverName
);
244 * Exported function for querying the DRI driver for a given screen.
246 * The returned char pointer points to a static array that will be
247 * overwritten by subsequent calls.
249 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
252 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
256 len
= strlen (driverName
);
259 memcpy (ret
, driverName
, len
+1);
268 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
270 * The returned char pointer points directly into the driver. Therefore
271 * it should be treated as a constant.
273 * If the driver was not found or does not support configuration NULL is
276 * Note: The driver remains opened after this function returns.
278 PUBLIC
const char *glXGetDriverConfig (const char *driverName
) {
279 void *handle
= OpenDriver (driverName
);
281 return dlsym (handle
, "__driConfigOptions");
287 filter_modes( __GLcontextModes
** server_modes
,
288 const __GLcontextModes
* driver_modes
)
290 __GLcontextModes
* m
;
291 __GLcontextModes
** prev_next
;
292 const __GLcontextModes
* check
;
294 if (driver_modes
== NULL
) {
295 fprintf(stderr
, "libGL warning: 3D driver returned no fbconfigs.\n");
299 /* For each mode in server_modes, check to see if a matching mode exists
300 * in driver_modes. If not, then the mode is not available.
303 prev_next
= server_modes
;
304 for ( m
= *prev_next
; m
!= NULL
; m
= *prev_next
) {
305 GLboolean do_delete
= GL_TRUE
;
307 for ( check
= driver_modes
; check
!= NULL
; check
= check
->next
) {
308 if ( _gl_context_modes_are_same( m
, check
) ) {
309 do_delete
= GL_FALSE
;
314 /* The 3D has to support all the modes that match the GLX visuals
315 * sent from the X server.
317 if ( do_delete
&& (m
->visualID
!= 0) ) {
318 do_delete
= GL_FALSE
;
320 /* don't warn for this visual (Novell #247471 / X.Org #6689) */
321 if (m
->visualRating
!= GLX_NON_CONFORMANT_CONFIG
) {
322 fprintf(stderr
, "libGL warning: 3D driver claims to not "
323 "support visual 0x%02x\n", m
->visualID
);
328 *prev_next
= m
->next
;
331 _gl_context_modes_destroy( m
);
334 prev_next
= & m
->next
;
339 #ifdef XDAMAGE_1_1_INTERFACE
340 static GLboolean
has_damage_post(Display
*dpy
)
342 static GLboolean inited
= GL_FALSE
;
343 static GLboolean has_damage
;
348 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
349 major
== 1 && minor
>= 1)
351 has_damage
= GL_TRUE
;
353 has_damage
= GL_FALSE
;
360 #endif /* XDAMAGE_1_1_INTERFACE */
362 static void __glXReportDamage(__DRIdrawable
*driDraw
,
364 drm_clip_rect_t
*rects
, int num_rects
,
365 GLboolean front_buffer
)
367 #ifdef XDAMAGE_1_1_INTERFACE
369 XserverRegion region
;
372 __GLXdrawable
*glxDraw
=
373 containerOf(driDraw
, __GLXdrawable
, driDrawable
);
374 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
375 Display
*dpy
= psc
->dpy
;
378 if (!has_damage_post(dpy
))
384 drawable
= RootWindow(dpy
, psc
->scr
);
388 drawable
= glxDraw
->drawable
;
391 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
395 for (i
= 0; i
< num_rects
; i
++) {
396 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
397 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
398 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
399 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
401 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
403 XDamageAdd(dpy
, drawable
, region
);
404 XFixesDestroyRegion(dpy
, region
);
409 __glXDRIGetDrawableInfo(__DRIdrawable
*drawable
,
410 unsigned int *index
, unsigned int *stamp
,
411 int *X
, int *Y
, int *W
, int *H
,
412 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
413 int *backX
, int *backY
,
414 int *numBackClipRects
, drm_clip_rect_t
**pBackClipRects
)
416 __GLXdrawable
*glxDraw
=
417 containerOf(drawable
, __GLXdrawable
, driDrawable
);
418 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
419 Display
*dpy
= psc
->dpy
;
421 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
422 index
, stamp
, X
, Y
, W
, H
,
423 numClipRects
, pClipRects
,
425 numBackClipRects
, pBackClipRects
);
430 * Table of functions exported by the loader to the driver.
432 static const __DRIcontextModesExtension contextModesExtension
= {
433 { __DRI_CONTEXT_MODES
, __DRI_CONTEXT_MODES_VERSION
},
434 _gl_context_modes_create
,
435 _gl_context_modes_destroy
,
438 static const __DRIsystemTimeExtension systemTimeExtension
= {
439 { __DRI_SYSTEM_TIME
, __DRI_SYSTEM_TIME_VERSION
},
444 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
445 { __DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
446 __glXDRIGetDrawableInfo
449 static const __DRIdamageExtension damageExtension
= {
450 { __DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
454 static const __DRIextension
*loader_extensions
[] = {
455 &contextModesExtension
.base
,
456 &systemTimeExtension
.base
,
457 &getDrawableInfoExtension
.base
,
458 &damageExtension
.base
,
464 * Perform the required libGL-side initialization and call the client-side
465 * driver's \c __driCreateNewScreen function.
467 * \param dpy Display pointer.
468 * \param scrn Screen number on the display.
469 * \param psc DRI screen information.
470 * \param driDpy DRI display information.
471 * \param createNewScreen Pointer to the client-side driver's
472 * \c __driCreateNewScreen function.
473 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
474 * the client-side driver on success, or \c NULL on failure.
476 * \todo This function needs to be modified to remove context-modes from the
477 * list stored in the \c __GLXscreenConfigsRec to match the list
478 * returned by the client-side driver.
481 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
482 __GLXDRIdisplayPrivate
* driDpy
,
483 PFNCREATENEWSCREENFUNC createNewScreen
)
486 #ifndef GLX_USE_APPLEGL
488 drmAddress pSAREA
= MAP_FAILED
;
490 __DRIversion ddx_version
;
491 __DRIversion dri_version
;
492 __DRIversion drm_version
;
493 __DRIframebuffer framebuffer
;
496 const char * err_msg
;
497 const char * err_extra
;
499 dri_version
.major
= driDpy
->driMajor
;
500 dri_version
.minor
= driDpy
->driMinor
;
501 dri_version
.patch
= driDpy
->driPatch
;
504 err_msg
= "XF86DRIOpenConnection";
507 framebuffer
.base
= MAP_FAILED
;
508 framebuffer
.dev_priv
= NULL
;
510 if (XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
512 fd
= drmOpenOnce(NULL
,BusID
, &newlyopened
);
513 Xfree(BusID
); /* No longer needed */
515 err_msg
= "open DRM";
516 err_extra
= strerror( -fd
);
521 err_msg
= "drmGetMagic";
524 if (!drmGetMagic(fd
, &magic
)) {
525 drmVersionPtr version
= drmGetVersion(fd
);
527 drm_version
.major
= version
->version_major
;
528 drm_version
.minor
= version
->version_minor
;
529 drm_version
.patch
= version
->version_patchlevel
;
530 drmFreeVersion(version
);
533 drm_version
.major
= -1;
534 drm_version
.minor
= -1;
535 drm_version
.patch
= -1;
538 err_msg
= "XF86DRIAuthConnection";
539 if (!newlyopened
|| XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
543 * Get device name (like "tdfx") and the ddx version
544 * numbers. We'll check the version in each DRI driver's
545 * "createNewScreen" function.
547 err_msg
= "XF86DRIGetClientDriverName";
548 if (XF86DRIGetClientDriverName(dpy
, scrn
,
556 /* No longer needed. */
561 * Get device-specific info. pDevPriv will point to a struct
562 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
563 * that has information about the screen size, depth, pitch,
564 * ancilliary buffers, DRM mmap handles, etc.
566 err_msg
= "XF86DRIGetDeviceInfo";
567 if (XF86DRIGetDeviceInfo(dpy
, scrn
,
572 &framebuffer
.dev_priv_size
,
573 &framebuffer
.dev_priv
)) {
574 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
575 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
578 * Map the framebuffer region.
580 status
= drmMap(fd
, hFB
, framebuffer
.size
,
581 (drmAddressPtr
)&framebuffer
.base
);
583 err_msg
= "drmMap of framebuffer";
584 err_extra
= strerror( -status
);
588 * Map the SAREA region. Further mmap regions
589 * may be setup in each DRI driver's
590 * "createNewScreen" function.
592 status
= drmMap(fd
, hSAREA
, SAREA_MAX
,
595 err_msg
= "drmMap of sarea";
596 err_extra
= strerror( -status
);
599 __GLcontextModes
* driver_modes
= NULL
;
601 err_msg
= "InitDriver";
603 psp
= (*createNewScreen
)(scrn
,
614 filter_modes(&psc
->configs
, driver_modes
);
615 filter_modes(&psc
->visuals
, driver_modes
);
616 _gl_context_modes_destroy(driver_modes
);
627 if ( pSAREA
!= MAP_FAILED
) {
628 (void)drmUnmap(pSAREA
, SAREA_MAX
);
631 if ( framebuffer
.base
!= MAP_FAILED
) {
632 (void)drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
635 if ( framebuffer
.dev_priv
!= NULL
) {
636 Xfree(framebuffer
.dev_priv
);
640 (void)drmCloseOnce(fd
);
643 (void)XF86DRICloseConnection(dpy
, scrn
);
645 if ( err_extra
!= NULL
) {
646 fprintf(stderr
, "libGL error: %s failed (%s)\n", err_msg
,
650 fprintf(stderr
, "libGL error: %s failed\n", err_msg
);
653 fprintf(stderr
, "libGL error: reverting to (slow) indirect rendering\n");
655 #endif /* !GLX_USE_APPLEGL */
661 static void driCreateContext(__GLXscreenConfigs
*psc
,
662 const __GLcontextModes
*mode
,
664 GLXContext shareList
, int renderType
)
666 drm_context_t hwContext
;
667 __DRIcontext
*shared
;
669 if (psc
&& psc
->driScreen
.private) {
670 shared
= (shareList
!= NULL
) ? &shareList
->driContext
: NULL
;
672 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
674 &gc
->hwContextID
, &hwContext
))
675 /* gah, handle this better */
678 gc
->driContext
.private =
679 (*psc
->driScreen
.createNewContext
)( &psc
->driScreen
,
684 if (gc
->driContext
.private) {
685 gc
->isDirect
= GL_TRUE
;
686 gc
->screen
= mode
->screen
;
691 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, gc
->hwContextID
);
696 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
698 /* Free the direct rendering per screen data */
699 if (psc
->driScreen
.private)
700 (*psc
->driScreen
.destroyScreen
)(&psc
->driScreen
);
701 psc
->driScreen
.private = NULL
;
703 __glxHashDestroy(psc
->drawHash
);
705 dlclose(psc
->driver
);
708 static void driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
709 __GLXdisplayPrivate
*priv
)
711 PFNCREATENEWSCREENFUNC createNewScreen
;
712 __GLXDRIdisplayPrivate
*pdp
;
714 if (priv
->driDisplay
== NULL
)
717 /* Create drawable hash */
718 psc
->drawHash
= __glxHashCreate();
719 if ( psc
->drawHash
== NULL
)
722 /* Initialize per screen dynamic client GLX extensions */
723 psc
->ext_list_first_time
= GL_TRUE
;
725 psc
->driver
= driGetDriver(priv
->dpy
, screen
);
726 createNewScreen
= dlsym(psc
->driver
, createNewScreenName
);
727 if (createNewScreenName
== NULL
)
730 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
731 psc
->driScreen
.private =
732 CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
, createNewScreen
);
733 if (psc
->driScreen
.private != NULL
)
734 __glXScrEnableDRIExtension(psc
);
736 psc
->driDestroyScreen
= driDestroyScreen
;
737 psc
->driCreateContext
= driCreateContext
;
740 /* Called from __glXFreeDisplayPrivate.
742 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
748 * Allocate, initialize and return a __DRIdisplayPrivate object.
749 * This is called from __glXInitialize() when we are given a new
752 __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
754 __GLXDRIdisplayPrivate
*pdpyp
;
755 int eventBase
, errorBase
;
756 int major
, minor
, patch
;
758 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
762 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
766 pdpyp
= Xmalloc(sizeof *pdpyp
);
771 pdpyp
->driMajor
= major
;
772 pdpyp
->driMinor
= minor
;
773 pdpyp
->driPatch
= patch
;
775 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
776 pdpyp
->base
.createScreen
= driCreateScreen
;
778 return (void *)pdpyp
;
781 #endif /* GLX_DIRECT_RENDERING */