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
);
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 */
155 if (libPaths
== NULL
)
156 libPaths
= DEFAULT_DRIVER_DIR
;
159 for (p
= libPaths
; *p
; p
= next
) {
160 next
= strchr(p
, ':');
170 snprintf(realDriverName
, sizeof realDriverName
,
171 "%.*s/tls/%s_dri.so", len
, p
, driverName
);
172 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
173 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
176 if ( handle
== NULL
) {
177 snprintf(realDriverName
, sizeof realDriverName
,
178 "%.*s/%s_dri.so", len
, p
, driverName
);
179 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
180 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
183 if ( handle
!= NULL
)
186 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
190 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
200 * Given a display pointer and screen number, determine the name of
201 * the DRI driver for the screen. (I.e. "r128", "tdfx", etc).
202 * Return True for success, False for failure.
204 static Bool
GetDriverName(Display
*dpy
, int scrNum
, char **driverName
)
208 int driverMajor
, driverMinor
, driverPatch
;
212 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrNum
, &directCapable
)) {
213 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
216 if (!directCapable
) {
217 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
221 b
= XF86DRIGetClientDriverName(dpy
, scrNum
, &driverMajor
, &driverMinor
,
222 &driverPatch
, driverName
);
224 ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum
);
228 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
229 driverMajor
, driverMinor
, driverPatch
, *driverName
, scrNum
);
236 * Given a display pointer and screen number, return a __DRIdriver handle.
237 * Return NULL if anything goes wrong.
239 static void *driGetDriver(Display
*dpy
, int scrNum
)
244 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
245 ret
= OpenDriver(driverName
);
254 * Exported function for querying the DRI driver for a given screen.
256 * The returned char pointer points to a static array that will be
257 * overwritten by subsequent calls.
259 PUBLIC
const char *glXGetScreenDriver (Display
*dpy
, int scrNum
) {
262 if (GetDriverName(dpy
, scrNum
, &driverName
)) {
266 len
= strlen (driverName
);
269 memcpy (ret
, driverName
, len
+1);
278 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
280 * The returned char pointer points directly into the driver. Therefore
281 * it should be treated as a constant.
283 * If the driver was not found or does not support configuration NULL is
286 * Note: The driver remains opened after this function returns.
288 PUBLIC
const char *glXGetDriverConfig (const char *driverName
) {
289 void *handle
= OpenDriver (driverName
);
291 return dlsym (handle
, "__driConfigOptions");
297 filter_modes( __GLcontextModes
** server_modes
,
298 const __GLcontextModes
* driver_modes
)
300 __GLcontextModes
* m
;
301 __GLcontextModes
** prev_next
;
302 const __GLcontextModes
* check
;
304 if (driver_modes
== NULL
) {
305 fprintf(stderr
, "libGL warning: 3D driver returned no fbconfigs.\n");
309 /* For each mode in server_modes, check to see if a matching mode exists
310 * in driver_modes. If not, then the mode is not available.
313 prev_next
= server_modes
;
314 for ( m
= *prev_next
; m
!= NULL
; m
= *prev_next
) {
315 GLboolean do_delete
= GL_TRUE
;
317 for ( check
= driver_modes
; check
!= NULL
; check
= check
->next
) {
318 if ( _gl_context_modes_are_same( m
, check
) ) {
319 do_delete
= GL_FALSE
;
324 /* The 3D has to support all the modes that match the GLX visuals
325 * sent from the X server.
327 if ( do_delete
&& (m
->visualID
!= 0) ) {
328 do_delete
= GL_FALSE
;
330 /* don't warn for this visual (Novell #247471 / X.Org #6689) */
331 if (m
->visualRating
!= GLX_NON_CONFORMANT_CONFIG
) {
332 fprintf(stderr
, "libGL warning: 3D driver claims to not "
333 "support visual 0x%02x\n", m
->visualID
);
338 *prev_next
= m
->next
;
341 _gl_context_modes_destroy( m
);
344 prev_next
= & m
->next
;
349 #ifdef XDAMAGE_1_1_INTERFACE
350 static GLboolean
has_damage_post(Display
*dpy
)
352 static GLboolean inited
= GL_FALSE
;
353 static GLboolean has_damage
;
358 if (XDamageQueryVersion(dpy
, &major
, &minor
) &&
359 major
== 1 && minor
>= 1)
361 has_damage
= GL_TRUE
;
363 has_damage
= GL_FALSE
;
370 #endif /* XDAMAGE_1_1_INTERFACE */
372 static void __glXReportDamage(__DRIdrawable
*driDraw
,
374 drm_clip_rect_t
*rects
, int num_rects
,
375 GLboolean front_buffer
)
377 #ifdef XDAMAGE_1_1_INTERFACE
379 XserverRegion region
;
382 __GLXdrawable
*glxDraw
=
383 containerOf(driDraw
, __GLXdrawable
, driDrawable
);
384 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
385 Display
*dpy
= psc
->dpy
;
388 if (!has_damage_post(dpy
))
394 drawable
= RootWindow(dpy
, psc
->scr
);
398 drawable
= glxDraw
->drawable
;
401 xrects
= malloc(sizeof(XRectangle
) * num_rects
);
405 for (i
= 0; i
< num_rects
; i
++) {
406 xrects
[i
].x
= rects
[i
].x1
+ x_off
;
407 xrects
[i
].y
= rects
[i
].y1
+ y_off
;
408 xrects
[i
].width
= rects
[i
].x2
- rects
[i
].x1
;
409 xrects
[i
].height
= rects
[i
].y2
- rects
[i
].y1
;
411 region
= XFixesCreateRegion(dpy
, xrects
, num_rects
);
413 XDamageAdd(dpy
, drawable
, region
);
414 XFixesDestroyRegion(dpy
, region
);
419 __glXDRIGetDrawableInfo(__DRIdrawable
*drawable
,
420 unsigned int *index
, unsigned int *stamp
,
421 int *X
, int *Y
, int *W
, int *H
,
422 int *numClipRects
, drm_clip_rect_t
** pClipRects
,
423 int *backX
, int *backY
,
424 int *numBackClipRects
, drm_clip_rect_t
**pBackClipRects
)
426 __GLXDRIdrawable
*glxDraw
=
427 containerOf(drawable
, __GLXDRIdrawable
, driDrawable
);
428 __GLXscreenConfigs
*psc
= glxDraw
->psc
;
429 Display
*dpy
= psc
->dpy
;
431 return XF86DRIGetDrawableInfo(dpy
, psc
->scr
, glxDraw
->drawable
,
432 index
, stamp
, X
, Y
, W
, H
,
433 numClipRects
, pClipRects
,
435 numBackClipRects
, pBackClipRects
);
440 * Table of functions exported by the loader to the driver.
442 static const __DRIcontextModesExtension contextModesExtension
= {
443 { __DRI_CONTEXT_MODES
, __DRI_CONTEXT_MODES_VERSION
},
444 _gl_context_modes_create
,
445 _gl_context_modes_destroy
,
448 static const __DRIsystemTimeExtension systemTimeExtension
= {
449 { __DRI_SYSTEM_TIME
, __DRI_SYSTEM_TIME_VERSION
},
454 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension
= {
455 { __DRI_GET_DRAWABLE_INFO
, __DRI_GET_DRAWABLE_INFO_VERSION
},
456 __glXDRIGetDrawableInfo
459 static const __DRIdamageExtension damageExtension
= {
460 { __DRI_DAMAGE
, __DRI_DAMAGE_VERSION
},
464 static const __DRIextension
*loader_extensions
[] = {
465 &contextModesExtension
.base
,
466 &systemTimeExtension
.base
,
467 &getDrawableInfoExtension
.base
,
468 &damageExtension
.base
,
474 * Perform the required libGL-side initialization and call the client-side
475 * driver's \c __driCreateNewScreen function.
477 * \param dpy Display pointer.
478 * \param scrn Screen number on the display.
479 * \param psc DRI screen information.
480 * \param driDpy DRI display information.
481 * \param createNewScreen Pointer to the client-side driver's
482 * \c __driCreateNewScreen function.
483 * \returns A pointer to the \c __DRIscreenPrivate structure returned by
484 * the client-side driver on success, or \c NULL on failure.
486 * \todo This function needs to be modified to remove context-modes from the
487 * list stored in the \c __GLXscreenConfigsRec to match the list
488 * returned by the client-side driver.
491 CallCreateNewScreen(Display
*dpy
, int scrn
, __GLXscreenConfigs
*psc
,
492 __GLXDRIdisplayPrivate
* driDpy
,
493 PFNCREATENEWSCREENFUNC createNewScreen
)
496 #ifndef GLX_USE_APPLEGL
498 drmAddress pSAREA
= MAP_FAILED
;
500 __DRIversion ddx_version
;
501 __DRIversion dri_version
;
502 __DRIversion drm_version
;
503 __DRIframebuffer framebuffer
;
506 const char * err_msg
;
507 const char * err_extra
;
509 dri_version
.major
= driDpy
->driMajor
;
510 dri_version
.minor
= driDpy
->driMinor
;
511 dri_version
.patch
= driDpy
->driPatch
;
514 err_msg
= "XF86DRIOpenConnection";
517 framebuffer
.base
= MAP_FAILED
;
518 framebuffer
.dev_priv
= NULL
;
520 if (XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
522 fd
= drmOpenOnce(NULL
,BusID
, &newlyopened
);
523 Xfree(BusID
); /* No longer needed */
525 err_msg
= "open DRM";
526 err_extra
= strerror( -fd
);
531 err_msg
= "drmGetMagic";
534 if (!drmGetMagic(fd
, &magic
)) {
535 drmVersionPtr version
= drmGetVersion(fd
);
537 drm_version
.major
= version
->version_major
;
538 drm_version
.minor
= version
->version_minor
;
539 drm_version
.patch
= version
->version_patchlevel
;
540 drmFreeVersion(version
);
543 drm_version
.major
= -1;
544 drm_version
.minor
= -1;
545 drm_version
.patch
= -1;
548 err_msg
= "XF86DRIAuthConnection";
549 if (!newlyopened
|| XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
553 * Get device name (like "tdfx") and the ddx version
554 * numbers. We'll check the version in each DRI driver's
555 * "createNewScreen" function.
557 err_msg
= "XF86DRIGetClientDriverName";
558 if (XF86DRIGetClientDriverName(dpy
, scrn
,
566 /* No longer needed. */
571 * Get device-specific info. pDevPriv will point to a struct
572 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
573 * that has information about the screen size, depth, pitch,
574 * ancilliary buffers, DRM mmap handles, etc.
576 err_msg
= "XF86DRIGetDeviceInfo";
577 if (XF86DRIGetDeviceInfo(dpy
, scrn
,
582 &framebuffer
.dev_priv_size
,
583 &framebuffer
.dev_priv
)) {
584 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
585 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
588 * Map the framebuffer region.
590 status
= drmMap(fd
, hFB
, framebuffer
.size
,
591 (drmAddressPtr
)&framebuffer
.base
);
593 err_msg
= "drmMap of framebuffer";
594 err_extra
= strerror( -status
);
598 * Map the SAREA region. Further mmap regions
599 * may be setup in each DRI driver's
600 * "createNewScreen" function.
602 status
= drmMap(fd
, hSAREA
, SAREA_MAX
,
605 err_msg
= "drmMap of sarea";
606 err_extra
= strerror( -status
);
609 __GLcontextModes
* driver_modes
= NULL
;
611 err_msg
= "InitDriver";
613 psp
= (*createNewScreen
)(scrn
,
624 filter_modes(&psc
->configs
, driver_modes
);
625 filter_modes(&psc
->visuals
, driver_modes
);
626 _gl_context_modes_destroy(driver_modes
);
637 if ( pSAREA
!= MAP_FAILED
) {
638 (void)drmUnmap(pSAREA
, SAREA_MAX
);
641 if ( framebuffer
.base
!= MAP_FAILED
) {
642 (void)drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
645 if ( framebuffer
.dev_priv
!= NULL
) {
646 Xfree(framebuffer
.dev_priv
);
650 (void)drmCloseOnce(fd
);
653 (void)XF86DRICloseConnection(dpy
, scrn
);
655 if ( err_extra
!= NULL
) {
656 fprintf(stderr
, "libGL error: %s failed (%s)\n", err_msg
,
660 fprintf(stderr
, "libGL error: %s failed\n", err_msg
);
663 fprintf(stderr
, "libGL error: reverting to (slow) indirect rendering\n");
665 #endif /* !GLX_USE_APPLEGL */
670 static void driDestroyContext(__GLXDRIcontext
*context
,
671 __GLXscreenConfigs
*psc
, Display
*dpy
)
673 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
675 (*pcp
->driContext
.destroyContext
)(&pcp
->driContext
);
677 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
680 static Bool
driBindContext(__GLXDRIcontext
*context
,
681 __GLXDRIdrawable
*draw
, __GLXDRIdrawable
*read
)
683 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
685 return (*pcp
->driContext
.bindContext
)(&pcp
->driContext
,
690 static void driUnbindContext(__GLXDRIcontext
*context
)
692 __GLXDRIcontextPrivate
*pcp
= (__GLXDRIcontextPrivate
*) context
;
694 (*pcp
->driContext
.unbindContext
)(&pcp
->driContext
);
697 static __GLXDRIcontext
*driCreateContext(__GLXscreenConfigs
*psc
,
698 const __GLcontextModes
*mode
,
700 GLXContext shareList
, int renderType
)
702 __GLXDRIcontextPrivate
*pcp
, *pcp_shared
;
703 drm_context_t hwContext
;
704 __DRIcontext
*shared
= NULL
;
706 if (psc
&& psc
->driScreen
) {
708 pcp_shared
= (__GLXDRIcontextPrivate
*) shareList
->driContext
;
709 shared
= &pcp_shared
->driContext
;
712 pcp
= Xmalloc(sizeof *pcp
);
716 if (!XF86DRICreateContextWithConfig(psc
->dpy
, psc
->scr
,
718 &pcp
->hwContextID
, &hwContext
)) {
723 pcp
->driContext
.private =
724 (*psc
->__driScreen
.createNewContext
)(&psc
->__driScreen
,
729 if (pcp
->driContext
.private == NULL
) {
730 XF86DRIDestroyContext(psc
->dpy
, psc
->scr
, pcp
->hwContextID
);
735 pcp
->base
.destroyContext
= driDestroyContext
;
736 pcp
->base
.bindContext
= driBindContext
;
737 pcp
->base
.unbindContext
= driUnbindContext
;
745 static void driDestroyDrawable(__GLXDRIdrawable
*pdraw
)
747 __GLXscreenConfigs
*psc
= pdraw
->psc
;
749 (*pdraw
->driDrawable
.destroyDrawable
)(&pdraw
->driDrawable
);
750 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, pdraw
->drawable
);
754 static __GLXDRIdrawable
*driCreateDrawable(__GLXscreenConfigs
*psc
,
755 GLXDrawable drawable
,
758 __GLXDRIdrawable
*pdraw
;
759 drm_drawable_t hwDrawable
;
760 void *empty_attribute_list
= NULL
;
762 pdraw
= Xmalloc(sizeof(*pdraw
));
766 pdraw
->drawable
= drawable
;
769 if (!XF86DRICreateDrawable(psc
->dpy
, psc
->scr
, drawable
, &hwDrawable
))
772 /* Create a new drawable */
773 pdraw
->driDrawable
.private =
774 (*psc
->__driScreen
.createNewDrawable
)(&psc
->__driScreen
,
780 empty_attribute_list
);
782 if (!pdraw
->driDrawable
.private) {
783 XF86DRIDestroyDrawable(psc
->dpy
, psc
->scr
, drawable
);
788 pdraw
->destroyDrawable
= driDestroyDrawable
;
793 static void driDestroyScreen(__GLXscreenConfigs
*psc
)
795 /* Free the direct rendering per screen data */
796 if (psc
->__driScreen
.private)
797 (*psc
->__driScreen
.destroyScreen
)(&psc
->__driScreen
);
798 psc
->__driScreen
.private = NULL
;
800 dlclose(psc
->driver
);
803 static __GLXDRIscreen
*driCreateScreen(__GLXscreenConfigs
*psc
, int screen
,
804 __GLXdisplayPrivate
*priv
)
806 PFNCREATENEWSCREENFUNC createNewScreen
;
807 __GLXDRIdisplayPrivate
*pdp
;
810 psp
= Xmalloc(sizeof *psp
);
814 /* Initialize per screen dynamic client GLX extensions */
815 psc
->ext_list_first_time
= GL_TRUE
;
817 psc
->driver
= driGetDriver(priv
->dpy
, screen
);
818 createNewScreen
= dlsym(psc
->driver
, createNewScreenName
);
819 if (createNewScreenName
== NULL
)
822 pdp
= (__GLXDRIdisplayPrivate
*) priv
->driDisplay
;
823 psc
->__driScreen
.private =
824 CallCreateNewScreen(psc
->dpy
, screen
, psc
, pdp
, createNewScreen
);
825 if (psc
->__driScreen
.private != NULL
)
826 __glXScrEnableDRIExtension(psc
);
828 psp
->destroyScreen
= driDestroyScreen
;
829 psp
->createContext
= driCreateContext
;
830 psp
->createDrawable
= driCreateDrawable
;
835 /* Called from __glXFreeDisplayPrivate.
837 static void driDestroyDisplay(__GLXDRIdisplay
*dpy
)
843 * Allocate, initialize and return a __DRIdisplayPrivate object.
844 * This is called from __glXInitialize() when we are given a new
847 _X_HIDDEN __GLXDRIdisplay
*driCreateDisplay(Display
*dpy
)
849 __GLXDRIdisplayPrivate
*pdpyp
;
850 int eventBase
, errorBase
;
851 int major
, minor
, patch
;
853 if (!XF86DRIQueryExtension(dpy
, &eventBase
, &errorBase
)) {
857 if (!XF86DRIQueryVersion(dpy
, &major
, &minor
, &patch
)) {
861 pdpyp
= Xmalloc(sizeof *pdpyp
);
866 pdpyp
->driMajor
= major
;
867 pdpyp
->driMinor
= minor
;
868 pdpyp
->driPatch
= patch
;
870 pdpyp
->base
.destroyDisplay
= driDestroyDisplay
;
871 pdpyp
->base
.createScreen
= driCreateScreen
;
876 #endif /* GLX_DIRECT_RENDERING */