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 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate
;
64 struct __GLXDRIdisplayPrivateRec
{
68 ** XFree86-DRI version information
75 struct __GLXDRIcontextPrivateRec
{
77 __DRIcontext driContext
;
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"
86 static void InfoMessageF(const char *f
, ...)
91 if ((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) {
92 fprintf(stderr
, "libGL: ");
94 vfprintf(stderr
, f
, args
);
100 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
102 static void ErrorMessageF(const char *f
, ...)
107 if ((env
= getenv("LIBGL_DEBUG")) && !strstr(env
, "quiet")) {
108 fprintf(stderr
, "libGL error: ");
110 vfprintf(stderr
, f
, args
);
117 * Versioned name of the expected \c __driCreateNewScreen function.
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.
123 static const char createNewScreenName
[] = __DRI_CREATE_NEW_SCREEN_STRING
;
127 * Try to \c dlopen the named driver.
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.
133 * \param driverName - a name like "tdfx", "i810", "mga", etc.
136 * A handle from \c dlopen, or \c NULL if driver file not found.
138 static void *OpenDriver(const char *driverName
)
140 void *glhandle
, *handle
;
141 const char *libPaths
, *p
, *next
;
142 char realDriverName
[200];
145 /* Attempt to make sure libGL symbols will be visible to the driver */
146 glhandle
= dlopen("libGL.so.1", RTLD_NOW
| RTLD_GLOBAL
);
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");
153 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
157 for (p
= libPaths
; *p
; p
= next
) {
158 next
= strchr(p
, ':');
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
);
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
);
181 if ( handle
!= NULL
)
184 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
188 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
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.
202 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
206 int driverMajor
, driverMinor
, driverPatch
;
210 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
211 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
214 if (!directCapable
) {
215 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
219 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
220 &driverPatch
, driverName
);
222 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
226 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
227 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
234 * Given a display pointer and screen number, return a __DRIdriver handle.
235 * Return NULL if anything goes wrong.
237 static void *driGetDriver(Display
*dpy
, int scrNum
)
242 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
243 ret
= OpenDriver(driverName
);
252 * Exported function for querying the DRI driver for a given screen.
254 * The returned char pointer points to a static array that will be
255 * overwritten by subsequent calls.
257 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
260 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
264 len
= strlen (driverName
);
267 memcpy (ret
, driverName
, len
+1);
276 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
278 * The returned char pointer points directly into the driver. Therefore
279 * it should be treated as a constant.
281 * If the driver was not found or does not support configuration NULL is
284 * Note: The driver remains opened after this function returns.
286 PUBLIC
const char *glXGetDriverConfig (const char *driverName
) {
287 void *handle
= OpenDriver (driverName
);
289 return dlsym (handle
, "__driConfigOptions");
295 filter_modes( __GLcontextModes
** server_modes
,
296 const __GLcontextModes
* driver_modes
)
298 __GLcontextModes
* m
;
299 __GLcontextModes
** prev_next
;
300 const __GLcontextModes
* check
;
302 if (driver_modes
== NULL
) {
303 fprintf(stderr
, "libGL warning: 3D driver returned no fbconfigs.\n");
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.
311 prev_next
= server_modes
;
312 for ( m
= *prev_next
; m
!= NULL
; m
= *prev_next
) {
313 GLboolean do_delete
= GL_TRUE
;
315 for ( check
= driver_modes
; check
!= NULL
; check
= check
->next
) {
316 if ( _gl_context_modes_are_same( m
, check
) ) {
317 do_delete
= GL_FALSE
;
322 /* The 3D has to support all the modes that match the GLX visuals
323 * sent from the X server.
325 if ( do_delete
&& (m
->visualID
!= 0) ) {
326 do_delete
= GL_FALSE
;
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
);
336 *prev_next
= m
->next
;
339 _gl_context_modes_destroy( m
);
342 prev_next
= & m
->next
;
347 #ifdef XDAMAGE_1_1_INTERFACE
348 static GLboolean
has_damage_post(Display
*dpy
)
350 static GLboolean inited
= GL_FALSE
;
351 static GLboolean has_damage
;
356 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
357 major
== 1 && minor
>= 1)
359 has_damage
= GL_TRUE
;
361 has_damage
= GL_FALSE
;
368 #endif /* XDAMAGE_1_1_INTERFACE */
370 static void __glXReportDamage(__DRIdrawable
*driDraw
,
372 drm_clip_rect_t
*rects
, int num_rects
,
373 GLboolean front_buffer
)
375 #ifdef XDAMAGE_1_1_INTERFACE
377 XserverRegion region
;
380 __GLXdrawable
*glxDraw
=
381 containerOf(driDraw
, __GLXdrawable
, driDrawable
);
382 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
383 Display
*dpy
= psc
->dpy
;
386 if (!has_damage_post(dpy
))
392 drawable
= RootWindow(dpy
, psc
->scr
);
396 drawable
= glxDraw
->drawable
;
399 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
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
;
409 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
411 XDamageAdd(dpy
, drawable
, region
);
412 XFixesDestroyRegion(dpy
, region
);
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
)
424 __GLXDRIdrawable
*glxDraw
=
425 containerOf(drawable
, __GLXDRIdrawable
, driDrawable
);
426 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
427 Display
*dpy
= psc
->dpy
;
429 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
430 index
, stamp
, X
, Y
, W
, H
,
431 numClipRects
, pClipRects
,
433 numBackClipRects
, pBackClipRects
);
438 * Table of functions exported by the loader to the driver.
440 static const __DRIcontextModesExtension contextModesExtension
= {
441 { __DRI_CONTEXT_MODES
, __DRI_CONTEXT_MODES_VERSION
},
442 _gl_context_modes_create
,
443 _gl_context_modes_destroy
,
446 static const __DRIsystemTimeExtension systemTimeExtension
= {
447 { __DRI_SYSTEM_TIME
, __DRI_SYSTEM_TIME_VERSION
},
452 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
453 { __DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
454 __glXDRIGetDrawableInfo
457 static const __DRIdamageExtension damageExtension
= {
458 { __DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
462 static const __DRIextension
*loader_extensions
[] = {
463 &contextModesExtension
.base
,
464 &systemTimeExtension
.base
,
465 &getDrawableInfoExtension
.base
,
466 &damageExtension
.base
,
472 * Perform the required libGL-side initialization and call the client-side
473 * driver's \c __driCreateNewScreen function.
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.
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.
489 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
490 __GLXDRIdisplayPrivate
* driDpy
,
491 PFNCREATENEWSCREENFUNC createNewScreen
)
494 #ifndef GLX_USE_APPLEGL
496 drmAddress pSAREA
= MAP_FAILED
;
498 __DRIversion ddx_version
;
499 __DRIversion dri_version
;
500 __DRIversion drm_version
;
501 __DRIframebuffer framebuffer
;
504 const char * err_msg
;
505 const char * err_extra
;
507 dri_version
.major
= driDpy
->driMajor
;
508 dri_version
.minor
= driDpy
->driMinor
;
509 dri_version
.patch
= driDpy
->driPatch
;
512 err_msg
= "XF86DRIOpenConnection";
515 framebuffer
.base
= MAP_FAILED
;
516 framebuffer
.dev_priv
= NULL
;
518 if (XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
520 fd
= drmOpenOnce(NULL
,BusID
, &newlyopened
);
521 Xfree(BusID
); /* No longer needed */
523 err_msg
= "open DRM";
524 err_extra
= strerror( -fd
);
529 err_msg
= "drmGetMagic";
532 if (!drmGetMagic(fd
, &magic
)) {
533 drmVersionPtr version
= drmGetVersion(fd
);
535 drm_version
.major
= version
->version_major
;
536 drm_version
.minor
= version
->version_minor
;
537 drm_version
.patch
= version
->version_patchlevel
;
538 drmFreeVersion(version
);
541 drm_version
.major
= -1;
542 drm_version
.minor
= -1;
543 drm_version
.patch
= -1;
546 err_msg
= "XF86DRIAuthConnection";
547 if (!newlyopened
|| XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
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.
555 err_msg
= "XF86DRIGetClientDriverName";
556 if (XF86DRIGetClientDriverName(dpy
, scrn
,
564 /* No longer needed. */
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.
574 err_msg
= "XF86DRIGetDeviceInfo";
575 if (XF86DRIGetDeviceInfo(dpy
, scrn
,
580 &framebuffer
.dev_priv_size
,
581 &framebuffer
.dev_priv
)) {
582 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
583 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
586 * Map the framebuffer region.
588 status
= drmMap(fd
, hFB
, framebuffer
.size
,
589 (drmAddressPtr
)&framebuffer
.base
);
591 err_msg
= "drmMap of framebuffer";
592 err_extra
= strerror( -status
);
596 * Map the SAREA region. Further mmap regions
597 * may be setup in each DRI driver's
598 * "createNewScreen" function.
600 status
= drmMap(fd
, hSAREA
, SAREA_MAX
,
603 err_msg
= "drmMap of sarea";
604 err_extra
= strerror( -status
);
607 __GLcontextModes
* driver_modes
= NULL
;
609 err_msg
= "InitDriver";
611 psp
= (*createNewScreen
)(scrn
,
622 filter_modes(&psc
->configs
, driver_modes
);
623 filter_modes(&psc
->visuals
, driver_modes
);
624 _gl_context_modes_destroy(driver_modes
);
635 if ( pSAREA
!= MAP_FAILED
) {
636 (void)drmUnmap(pSAREA
, SAREA_MAX
);
639 if ( framebuffer
.base
!= MAP_FAILED
) {
640 (void)drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
643 if ( framebuffer
.dev_priv
!= NULL
) {
644 Xfree(framebuffer
.dev_priv
);
648 (void)drmCloseOnce(fd
);
651 (void)XF86DRICloseConnection(dpy
, scrn
);
653 if ( err_extra
!= NULL
) {
654 fprintf(stderr
, "libGL error: %s failed (%s)\n", err_msg
,
658 fprintf(stderr
, "libGL error: %s failed\n", err_msg
);
661 fprintf(stderr
, "libGL error: reverting to (slow) indirect rendering\n");
663 #endif /* !GLX_USE_APPLEGL */
668 static void driDestroyContext(__GLXDRIcontext
*context
,
669 __GLXscreenConfigs
*psc
, Display
*dpy
)
671 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
673 (*pcp
->driContext
.destroyContext
)(&pcp
->driContext
);
675 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
678 static Bool
driBindContext(__GLXDRIcontext
*context
,
679 __GLXDRIdrawable
*draw
, __GLXDRIdrawable
*read
)
681 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
683 return (*pcp
->driContext
.bindContext
)(&pcp
->driContext
,
688 static void driUnbindContext(__GLXDRIcontext
*context
)
690 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
692 (*pcp
->driContext
.unbindContext
)(&pcp
->driContext
);
695 static __GLXDRIcontext
*driCreateContext(__GLXscreenConfigs
*psc
,
696 const __GLcontextModes
*mode
,
698 GLXContext shareList
, int renderType
)
700 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
701 drm_context_t hwContext
;
702 __DRIcontext
*shared
= NULL
;
704 if (psc
&& psc
->driScreen
) {
706 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
707 shared
= &pcp_shared
->driContext
;
710 pcp
= Xmalloc(sizeof *pcp
);
714 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
716 &pcp
->hwContextID
, &hwContext
)) {
721 pcp
->driContext
.private =
722 (*psc
->__driScreen
.createNewContext
)(&psc
->__driScreen
,
727 if (pcp
->driContext
.private == NULL
) {
728 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
733 pcp
->base
.destroyContext
= driDestroyContext
;
734 pcp
->base
.bindContext
= driBindContext
;
735 pcp
->base
.unbindContext
= driUnbindContext
;
744 static __GLXDRIdrawable
*driCreateDrawable(__GLXscreenConfigs
*psc
,
745 GLXDrawable drawable
,
748 __GLXDRIdrawable
*pdraw
;
749 drm_drawable_t hwDrawable
;
750 void *empty_attribute_list
= NULL
;
752 pdraw
= Xmalloc(sizeof(*pdraw
));
756 pdraw
->drawable
= drawable
;
759 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
762 /* Create a new drawable */
763 pdraw
->driDrawable
.private =
764 (*psc
->__driScreen
.createNewDrawable
)(&psc
->__driScreen
,
769 empty_attribute_list
);
771 if (!pdraw
->driDrawable
.private) {
772 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
777 if (__glxHashInsert(psc
->drawHash
, drawable
, pdraw
)) {
778 (*pdraw
->driDrawable
.destroyDrawable
)(&pdraw
->driDrawable
);
779 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
787 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
789 /* Free the direct rendering per screen data */
790 if (psc
->__driScreen
.private)
791 (*psc
->__driScreen
.destroyScreen
)(&psc
->__driScreen
);
792 psc
->__driScreen
.private = NULL
;
794 __glxHashDestroy(psc
->drawHash
);
796 dlclose(psc
->driver
);
799 static __GLXDRIscreen
*driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
800 __GLXdisplayPrivate
*priv
)
802 PFNCREATENEWSCREENFUNC createNewScreen
;
803 __GLXDRIdisplayPrivate
*pdp
;
806 psp
= Xmalloc(sizeof *psp
);
810 /* Create drawable hash */
811 psc
->drawHash
= __glxHashCreate();
812 if ( psc
->drawHash
== NULL
)
815 /* Initialize per screen dynamic client GLX extensions */
816 psc
->ext_list_first_time
= GL_TRUE
;
818 psc
->driver
= driGetDriver(priv
->dpy
, screen
);
819 createNewScreen
= dlsym(psc
->driver
, createNewScreenName
);
820 if (createNewScreenName
== NULL
)
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
);
829 psp
->destroyScreen
= driDestroyScreen
;
830 psp
->createContext
= driCreateContext
;
831 psp
->createDrawable
= driCreateDrawable
;
836 /* Called from __glXFreeDisplayPrivate.
838 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
844 * Allocate, initialize and return a __DRIdisplayPrivate object.
845 * This is called from __glXInitialize() when we are given a new
848 __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
850 __GLXDRIdisplayPrivate
*pdpyp
;
851 int eventBase
, errorBase
;
852 int major
, minor
, patch
;
854 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
858 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
862 pdpyp
= Xmalloc(sizeof *pdpyp
);
867 pdpyp
->driMajor
= major
;
868 pdpyp
->driMinor
= minor
;
869 pdpyp
->driPatch
= patch
;
871 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
872 pdpyp
->base
.createScreen
= driCreateScreen
;
877 #endif /* GLX_DIRECT_RENDERING */