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>
41 #include <X11/extensions/Xfixes.h>
42 #include <X11/extensions/Xdamage.h>
44 #include "glxclient.h"
49 #include <sys/types.h>
51 #include "glcontextmodes.h"
63 typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate
;
64 typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate
;
66 struct __GLXDRIdisplayPrivateRec
{
70 ** XFree86-DRI version information
77 struct __GLXDRIcontextPrivateRec
{
79 __DRIcontext driContext
;
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"
88 static void InfoMessageF(const char *f
, ...)
93 if ((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) {
94 fprintf(stderr
, "libGL: ");
96 vfprintf(stderr
, f
, args
);
102 * Print error to stderr, unless LIBGL_DEBUG=="quiet".
104 static void ErrorMessageF(const char *f
, ...)
109 if ((env
= getenv("LIBGL_DEBUG")) && !strstr(env
, "quiet")) {
110 fprintf(stderr
, "libGL error: ");
112 vfprintf(stderr
, f
, args
);
119 * Versioned name of the expected \c __driCreateNewScreen function.
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.
125 static const char createNewScreenName
[] = __DRI_CREATE_NEW_SCREEN_STRING
;
129 * Try to \c dlopen the named driver.
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.
135 * \param driverName - a name like "tdfx", "i810", "mga", etc.
138 * A handle from \c dlopen, or \c NULL if driver file not found.
140 static void *OpenDriver(const char *driverName
)
142 void *glhandle
, *handle
;
143 const char *libPaths
, *p
, *next
;
144 char realDriverName
[200];
147 /* Attempt to make sure libGL symbols will be visible to the driver */
148 glhandle
= dlopen("libGL.so.1", RTLD_NOW
| RTLD_GLOBAL
);
151 if (geteuid() == getuid()) {
152 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
153 libPaths
= getenv("LIBGL_DRIVERS_PATH");
155 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
157 if (libPaths
== NULL
)
158 libPaths
= DEFAULT_DRIVER_DIR
;
161 for (p
= libPaths
; *p
; p
= next
) {
162 next
= strchr(p
, ':');
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
);
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
);
185 if ( handle
!= NULL
)
188 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
192 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
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.
206 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
210 int driverMajor
, driverMinor
, driverPatch
;
214 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
215 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
218 if (!directCapable
) {
219 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
223 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
224 &driverPatch
, driverName
);
226 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
230 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
231 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
238 * Given a display pointer and screen number, return a __DRIdriver handle.
239 * Return NULL if anything goes wrong.
241 static void *driGetDriver(Display
*dpy
, int scrNum
)
246 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
247 ret
= OpenDriver(driverName
);
256 * Exported function for querying the DRI driver for a given screen.
258 * The returned char pointer points to a static array that will be
259 * overwritten by subsequent calls.
261 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
264 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
268 len
= strlen (driverName
);
271 memcpy (ret
, driverName
, len
+1);
280 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
282 * The returned char pointer points directly into the driver. Therefore
283 * it should be treated as a constant.
285 * If the driver was not found or does not support configuration NULL is
288 * Note: The driver remains opened after this function returns.
290 PUBLIC
const char *glXGetDriverConfig (const char *driverName
) {
291 void *handle
= OpenDriver (driverName
);
293 return dlsym (handle
, "__driConfigOptions");
299 filter_modes( __GLcontextModes
** server_modes
,
300 const __GLcontextModes
* driver_modes
)
302 __GLcontextModes
* m
;
303 __GLcontextModes
** prev_next
;
304 const __GLcontextModes
* check
;
306 if (driver_modes
== NULL
) {
307 fprintf(stderr
, "libGL warning: 3D driver returned no fbconfigs.\n");
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.
315 prev_next
= server_modes
;
316 for ( m
= *prev_next
; m
!= NULL
; m
= *prev_next
) {
317 GLboolean do_delete
= GL_TRUE
;
319 for ( check
= driver_modes
; check
!= NULL
; check
= check
->next
) {
320 if ( _gl_context_modes_are_same( m
, check
) ) {
321 do_delete
= GL_FALSE
;
326 /* The 3D has to support all the modes that match the GLX visuals
327 * sent from the X server.
329 if ( do_delete
&& (m
->visualID
!= 0) ) {
330 do_delete
= GL_FALSE
;
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
);
340 *prev_next
= m
->next
;
343 _gl_context_modes_destroy( m
);
346 prev_next
= & m
->next
;
351 #ifdef XDAMAGE_1_1_INTERFACE
352 static GLboolean
has_damage_post(Display
*dpy
)
354 static GLboolean inited
= GL_FALSE
;
355 static GLboolean has_damage
;
360 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
361 major
== 1 && minor
>= 1)
363 has_damage
= GL_TRUE
;
365 has_damage
= GL_FALSE
;
372 #endif /* XDAMAGE_1_1_INTERFACE */
374 static void __glXReportDamage(__DRIdrawable
*driDraw
,
376 drm_clip_rect_t
*rects
, int num_rects
,
377 GLboolean front_buffer
)
379 #ifdef XDAMAGE_1_1_INTERFACE
381 XserverRegion region
;
384 __GLXDRIdrawable
*glxDraw
=
385 containerOf(driDraw
, __GLXDRIdrawable
, driDrawable
);
386 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
387 Display
*dpy
= psc
->dpy
;
390 if (!has_damage_post(dpy
))
396 drawable
= RootWindow(dpy
, psc
->scr
);
400 drawable
= glxDraw
->drawable
;
403 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
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
;
413 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
415 XDamageAdd(dpy
, drawable
, region
);
416 XFixesDestroyRegion(dpy
, region
);
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
)
428 __GLXDRIdrawable
*glxDraw
=
429 containerOf(drawable
, __GLXDRIdrawable
, driDrawable
);
430 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
431 Display
*dpy
= psc
->dpy
;
433 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
434 index
, stamp
, X
, Y
, W
, H
,
435 numClipRects
, pClipRects
,
437 numBackClipRects
, pBackClipRects
);
442 * Table of functions exported by the loader to the driver.
444 static const __DRIcontextModesExtension contextModesExtension
= {
445 { __DRI_CONTEXT_MODES
, __DRI_CONTEXT_MODES_VERSION
},
446 _gl_context_modes_create
,
447 _gl_context_modes_destroy
,
450 static const __DRIsystemTimeExtension systemTimeExtension
= {
451 { __DRI_SYSTEM_TIME
, __DRI_SYSTEM_TIME_VERSION
},
456 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
457 { __DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
458 __glXDRIGetDrawableInfo
461 static const __DRIdamageExtension damageExtension
= {
462 { __DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
466 static const __DRIextension
*loader_extensions
[] = {
467 &contextModesExtension
.base
,
468 &systemTimeExtension
.base
,
469 &getDrawableInfoExtension
.base
,
470 &damageExtension
.base
,
476 * Perform the required libGL-side initialization and call the client-side
477 * driver's \c __driCreateNewScreen function.
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.
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.
493 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
494 __GLXDRIdisplayPrivate
* driDpy
,
495 PFNCREATENEWSCREENFUNC createNewScreen
)
498 #ifndef GLX_USE_APPLEGL
500 drmAddress pSAREA
= MAP_FAILED
;
502 __DRIversion ddx_version
;
503 __DRIversion dri_version
;
504 __DRIversion drm_version
;
505 __DRIframebuffer framebuffer
;
508 const char * err_msg
;
509 const char * err_extra
;
511 dri_version
.major
= driDpy
->driMajor
;
512 dri_version
.minor
= driDpy
->driMinor
;
513 dri_version
.patch
= driDpy
->driPatch
;
516 err_msg
= "XF86DRIOpenConnection";
519 framebuffer
.base
= MAP_FAILED
;
520 framebuffer
.dev_priv
= NULL
;
522 if (XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
524 fd
= drmOpenOnce(NULL
,BusID
, &newlyopened
);
525 Xfree(BusID
); /* No longer needed */
527 err_msg
= "open DRM";
528 err_extra
= strerror( -fd
);
533 err_msg
= "drmGetMagic";
536 if (!drmGetMagic(fd
, &magic
)) {
537 drmVersionPtr version
= drmGetVersion(fd
);
539 drm_version
.major
= version
->version_major
;
540 drm_version
.minor
= version
->version_minor
;
541 drm_version
.patch
= version
->version_patchlevel
;
542 drmFreeVersion(version
);
545 drm_version
.major
= -1;
546 drm_version
.minor
= -1;
547 drm_version
.patch
= -1;
550 err_msg
= "XF86DRIAuthConnection";
551 if (!newlyopened
|| XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
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.
559 err_msg
= "XF86DRIGetClientDriverName";
560 if (XF86DRIGetClientDriverName(dpy
, scrn
,
568 /* No longer needed. */
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.
578 err_msg
= "XF86DRIGetDeviceInfo";
579 if (XF86DRIGetDeviceInfo(dpy
, scrn
,
584 &framebuffer
.dev_priv_size
,
585 &framebuffer
.dev_priv
)) {
586 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
587 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
590 * Map the framebuffer region.
592 status
= drmMap(fd
, hFB
, framebuffer
.size
,
593 (drmAddressPtr
)&framebuffer
.base
);
595 err_msg
= "drmMap of framebuffer";
596 err_extra
= strerror( -status
);
600 * Map the SAREA region. Further mmap regions
601 * may be setup in each DRI driver's
602 * "createNewScreen" function.
604 status
= drmMap(fd
, hSAREA
, SAREA_MAX
,
607 err_msg
= "drmMap of sarea";
608 err_extra
= strerror( -status
);
611 __GLcontextModes
* driver_modes
= NULL
;
613 err_msg
= "InitDriver";
615 psp
= (*createNewScreen
)(scrn
,
626 filter_modes(&psc
->configs
, driver_modes
);
627 filter_modes(&psc
->visuals
, driver_modes
);
628 _gl_context_modes_destroy(driver_modes
);
639 if ( pSAREA
!= MAP_FAILED
) {
640 (void)drmUnmap(pSAREA
, SAREA_MAX
);
643 if ( framebuffer
.base
!= MAP_FAILED
) {
644 (void)drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
647 if ( framebuffer
.dev_priv
!= NULL
) {
648 Xfree(framebuffer
.dev_priv
);
652 (void)drmCloseOnce(fd
);
655 (void)XF86DRICloseConnection(dpy
, scrn
);
657 if ( err_extra
!= NULL
) {
658 fprintf(stderr
, "libGL error: %s failed (%s)\n", err_msg
,
662 fprintf(stderr
, "libGL error: %s failed\n", err_msg
);
665 fprintf(stderr
, "libGL error: reverting to (slow) indirect rendering\n");
667 #endif /* !GLX_USE_APPLEGL */
672 static void driDestroyContext(__GLXDRIcontext
*context
,
673 __GLXscreenConfigs
*psc
, Display
*dpy
)
675 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
677 (*pcp
->driContext
.destroyContext
)(&pcp
->driContext
);
679 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
682 static Bool
driBindContext(__GLXDRIcontext
*context
,
683 __GLXDRIdrawable
*draw
, __GLXDRIdrawable
*read
)
685 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
687 return (*pcp
->driContext
.bindContext
)(&pcp
->driContext
,
692 static void driUnbindContext(__GLXDRIcontext
*context
)
694 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
696 (*pcp
->driContext
.unbindContext
)(&pcp
->driContext
);
699 static __GLXDRIcontext
*driCreateContext(__GLXscreenConfigs
*psc
,
700 const __GLcontextModes
*mode
,
702 GLXContext shareList
, int renderType
)
704 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
705 drm_context_t hwContext
;
706 __DRIcontext
*shared
= NULL
;
708 if (psc
&& psc
->driScreen
) {
710 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
711 shared
= &pcp_shared
->driContext
;
714 pcp
= Xmalloc(sizeof *pcp
);
718 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
720 &pcp
->hwContextID
, &hwContext
)) {
725 pcp
->driContext
.private =
726 (*psc
->__driScreen
.createNewContext
)(&psc
->__driScreen
,
731 if (pcp
->driContext
.private == NULL
) {
732 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
737 pcp
->base
.destroyContext
= driDestroyContext
;
738 pcp
->base
.bindContext
= driBindContext
;
739 pcp
->base
.unbindContext
= driUnbindContext
;
747 static void driDestroyDrawable(__GLXDRIdrawable
*pdraw
)
749 __GLXscreenConfigs
*psc
= pdraw
->psc
;
751 (*pdraw
->driDrawable
.destroyDrawable
)(&pdraw
->driDrawable
);
752 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
756 static __GLXDRIdrawable
*driCreateDrawable(__GLXscreenConfigs
*psc
,
757 GLXDrawable drawable
,
760 __GLXDRIdrawable
*pdraw
;
761 drm_drawable_t hwDrawable
;
762 void *empty_attribute_list
= NULL
;
764 pdraw
= Xmalloc(sizeof(*pdraw
));
768 pdraw
->drawable
= drawable
;
771 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
774 /* Create a new drawable */
775 pdraw
->driDrawable
.private =
776 (*psc
->__driScreen
.createNewDrawable
)(&psc
->__driScreen
,
782 empty_attribute_list
);
784 if (!pdraw
->driDrawable
.private) {
785 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
790 pdraw
->destroyDrawable
= driDestroyDrawable
;
795 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
797 /* Free the direct rendering per screen data */
798 if (psc
->__driScreen
.private)
799 (*psc
->__driScreen
.destroyScreen
)(&psc
->__driScreen
);
800 psc
->__driScreen
.private = NULL
;
802 dlclose(psc
->driver
);
805 static __GLXDRIscreen
*driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
806 __GLXdisplayPrivate
*priv
)
808 PFNCREATENEWSCREENFUNC createNewScreen
;
809 __GLXDRIdisplayPrivate
*pdp
;
812 psp
= Xmalloc(sizeof *psp
);
816 /* Initialize per screen dynamic client GLX extensions */
817 psc
->ext_list_first_time
= GL_TRUE
;
819 psc
->driver
= driGetDriver(priv
->dpy
, screen
);
820 createNewScreen
= dlsym(psc
->driver
, createNewScreenName
);
821 if (createNewScreenName
== NULL
)
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
);
830 psp
->destroyScreen
= driDestroyScreen
;
831 psp
->createContext
= driCreateContext
;
832 psp
->createDrawable
= driCreateDrawable
;
837 /* Called from __glXFreeDisplayPrivate.
839 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
845 * Allocate, initialize and return a __DRIdisplayPrivate object.
846 * This is called from __glXInitialize() when we are given a new
849 _X_HIDDEN __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
851 __GLXDRIdisplayPrivate
*pdpyp
;
852 int eventBase
, errorBase
;
853 int major
, minor
, patch
;
855 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
859 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
863 pdpyp
= Xmalloc(sizeof *pdpyp
);
868 pdpyp
->driMajor
= major
;
869 pdpyp
->driMinor
= minor
;
870 pdpyp
->driPatch
= patch
;
872 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
873 pdpyp
->base
.createScreen
= driCreateScreen
;
878 #endif /* GLX_DIRECT_RENDERING */