1 /* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
4 * DRI utility functions.
6 * This module acts as glue between GLX and the actual hardware driver. A DRI
7 * driver doesn't really \e have to use any of this - it's optional. But, some
8 * useful stuff is done here that otherwise would have to be duplicated in most
11 * Basically, these utility functions take care of some of the dirty details of
12 * screen initialization, context creation, context binding, DRM setup, etc.
14 * These functions are compiled into each DRI driver so libGL.so knows nothing
18 * When \c DRI_NEW_INTERFACE_ONLY is defined, code is built / not built so
19 * that only the "new" libGL-to-driver interfaces are supported. This breaks
20 * backwards compatability. However, this may be necessary when DRI drivers
21 * are built to be used in non-XFree86 environments.
23 * \todo There are still some places in the code that need to be wrapped with
24 * \c DRI_NEW_INTERFACE_ONLY.
28 #ifdef GLX_DIRECT_RENDERING
35 #include <X11/Xlibint.h>
42 #include "glcontextmodes.h"
44 /*#define DRI_NEW_INTERFACE_ONLY*/
47 * This is used in a couple of places that call \c driCreateNewDrawable.
49 static const int empty_attribute_list
[1] = { None
};
52 * Function used to determine if a drawable (window) still exists. Ideally
53 * this function comes from libGL. With older versions of libGL from XFree86
54 * we can fall-back to an internal version.
56 * \sa __driWindowExists __glXWindowExists
58 static PFNGLXWINDOWEXISTSPROC window_exists
;
60 typedef Bool (*PFNGLXCREATECONTEXTWITHCONFIGPROC
)( Display
*, int, int, void *,
63 static PFNGLXCREATECONTEXTWITHCONFIGPROC create_context_with_config
;
66 * Cached copy of the internal API version used by libGL and the client-side
69 static int api_ver
= 0;
71 /* forward declarations */
72 static int driQueryFrameTracking( Display
* dpy
, void * priv
,
73 int64_t * sbc
, int64_t * missedFrames
, float * lastMissedUsage
,
76 static void *driCreateNewDrawable(Display
*dpy
, const __GLcontextModes
*modes
,
77 GLXDrawable draw
, __DRIdrawable
*pdraw
, int renderType
, const int *attrs
);
79 static void driDestroyDrawable(Display
*dpy
, void *drawablePrivate
);
85 static Bool
driFeatureOn(const char *name
)
87 char *env
= getenv(name
);
89 if (!env
) return GL_FALSE
;
90 if (!strcasecmp(env
, "enable")) return GL_TRUE
;
91 if (!strcasecmp(env
, "1")) return GL_TRUE
;
92 if (!strcasecmp(env
, "on")) return GL_TRUE
;
93 if (!strcasecmp(env
, "true")) return GL_TRUE
;
94 if (!strcasecmp(env
, "t")) return GL_TRUE
;
95 if (!strcasecmp(env
, "yes")) return GL_TRUE
;
96 if (!strcasecmp(env
, "y")) return GL_TRUE
;
100 #endif /* not_defined */
104 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
107 * Is called from the drivers.
109 * \param f \c printf like format string.
112 __driUtilMessage(const char *f
, ...)
116 if (getenv("LIBGL_DEBUG")) {
117 fprintf(stderr
, "libGL error: \n");
119 vfprintf(stderr
, f
, args
);
121 fprintf(stderr
, "\n");
126 /*****************************************************************/
127 /** \name Visual utility functions */
128 /*****************************************************************/
131 #ifndef DRI_NEW_INTERFACE_ONLY
133 * Find a \c __GLcontextModes structure matching the given visual ID.
135 * \param dpy Display to search for a matching configuration.
136 * \param scrn Screen number on \c dpy to be searched.
137 * \param vid Desired \c VisualID to find.
139 * \returns A pointer to a \c __GLcontextModes structure that matches \c vid,
140 * if found, or \c NULL if no match is found.
142 static const __GLcontextModes
*
143 findConfigMode(Display
*dpy
, int scrn
, VisualID vid
,
144 const __DRIscreen
* pDRIScreen
)
146 if ( (pDRIScreen
!= NULL
) && (pDRIScreen
->private != NULL
) ) {
147 const __DRIscreenPrivate
* const psp
=
148 (const __DRIscreenPrivate
*) pDRIScreen
->private;
150 return _gl_context_modes_find_visual( psp
->modes
, vid
);
158 * This function is a hack to work-around old versions of libGL.so that
159 * do not export \c XF86DRICreateContextWithConfig. I would modify the
160 * code to just use this function, but the stand-alone driver (i.e., DRI
161 * drivers that are built to work without XFree86) shouldn't have to know
162 * about X structures like a \c Visual.
165 fake_XF86DRICreateContextWithConfig( Display
* dpy
, int screen
, int configID
,
166 XID
* context
, drmContextPtr hHWContext
)
170 vis
.visualid
= configID
;
171 return XF86DRICreateContext( dpy
, screen
, & vis
, context
, hHWContext
);
173 #endif /* DRI_NEW_INTERFACE_ONLY */
178 /*****************************************************************/
179 /** \name Drawable list management */
180 /*****************************************************************/
183 static Bool
__driAddDrawable(void *drawHash
, __DRIdrawable
*pdraw
)
185 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)pdraw
->private;
187 if (drmHashInsert(drawHash
, pdp
->draw
, pdraw
))
193 static __DRIdrawable
*__driFindDrawable(void *drawHash
, GLXDrawable draw
)
196 __DRIdrawable
*pdraw
;
198 retcode
= drmHashLookup(drawHash
, draw
, (void **)&pdraw
);
205 static void __driRemoveDrawable(void *drawHash
, __DRIdrawable
*pdraw
)
208 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)pdraw
->private;
210 retcode
= drmHashLookup(drawHash
, pdp
->draw
, (void **)&pdraw
);
211 if (!retcode
) { /* Found */
212 drmHashDelete(drawHash
, pdp
->draw
);
216 #ifndef DRI_NEW_INTERFACE_ONLY
217 static Bool __driWindowExistsFlag
;
219 static int __driWindowExistsErrorHandler(Display
*dpy
, XErrorEvent
*xerr
)
221 if (xerr
->error_code
== BadWindow
) {
222 __driWindowExistsFlag
= GL_FALSE
;
228 * Determine if a window associated with a \c GLXDrawable exists on the
231 * \param dpy Display associated with the drawable to be queried.
232 * \param draw \c GLXDrawable to test.
234 * \returns \c GL_TRUE if a window exists that is associated with \c draw,
235 * otherwise \c GL_FALSE is returned.
237 * \warning This function is not currently thread-safe.
240 * \c __glXWindowExists (from libGL) is prefered over this function. Starting
241 * with the next major release of XFree86, this function will be removed.
242 * Even now this function is no longer directly called. Instead it is called
243 * via a function pointer if and only if \c __glXWindowExists does not exist.
245 * \sa __glXWindowExists glXGetProcAddress window_exists
247 static Bool
__driWindowExists(Display
*dpy
, GLXDrawable draw
)
249 XWindowAttributes xwa
;
250 int (*oldXErrorHandler
)(Display
*, XErrorEvent
*);
252 XSync(dpy
, GL_FALSE
);
253 __driWindowExistsFlag
= GL_TRUE
;
254 oldXErrorHandler
= XSetErrorHandler(__driWindowExistsErrorHandler
);
255 XGetWindowAttributes(dpy
, draw
, &xwa
); /* dummy request */
256 XSetErrorHandler(oldXErrorHandler
);
257 return __driWindowExistsFlag
;
259 #endif /* DRI_NEW_INTERFACE_ONLY */
262 * Find drawables in the local hash that have been destroyed on the
265 * \param drawHash Hash-table containing all know drawables.
267 static void __driGarbageCollectDrawables(void *drawHash
)
270 __DRIdrawable
*pdraw
;
273 if (drmHashFirst(drawHash
, &draw
, (void **)&pdraw
)) {
275 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)pdraw
->private;
276 dpy
= pdp
->driScreenPriv
->display
;
277 if (! (*window_exists
)(dpy
, draw
)) {
278 /* Destroy the local drawable data in the hash table, if the
279 drawable no longer exists in the Xserver */
280 __driRemoveDrawable(drawHash
, pdraw
);
281 (*pdraw
->destroyDrawable
)(dpy
, pdraw
->private);
284 } while (drmHashNext(drawHash
, &draw
, (void **)&pdraw
));
291 /*****************************************************************/
292 /** \name Context (un)binding functions */
293 /*****************************************************************/
299 * \param dpy the display handle.
300 * \param scrn the screen number.
301 * \param draw drawable.
302 * \param read Current reading drawable.
305 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
308 * This function calls __DriverAPIRec::UnbindContext, and then decrements
309 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
312 * While casting the opaque private pointers associated with the parameters
313 * into their respective real types it also assures they are not \c NULL.
315 static Bool
driUnbindContext2(Display
*dpy
, int scrn
,
316 GLXDrawable draw
, GLXDrawable read
,
319 __DRIscreen
*pDRIScreen
;
320 __DRIdrawable
*pdraw
;
321 __DRIdrawable
*pread
;
322 __DRIcontextPrivate
*pcp
;
323 __DRIscreenPrivate
*psp
;
324 __DRIdrawablePrivate
*pdp
;
325 __DRIdrawablePrivate
*prp
;
328 ** Assume error checking is done properly in glXMakeCurrent before
329 ** calling driUnbindContext2.
332 if (gc
== NULL
|| draw
== None
|| read
== None
) {
337 pDRIScreen
= __glXFindDRIScreen(dpy
, scrn
);
338 if ( (pDRIScreen
== NULL
) || (pDRIScreen
->private == NULL
) ) {
343 psp
= (__DRIscreenPrivate
*)pDRIScreen
->private;
344 pcp
= (__DRIcontextPrivate
*)gc
->driContext
.private;
346 pdraw
= __driFindDrawable(psp
->drawHash
, draw
);
351 pdp
= (__DRIdrawablePrivate
*)pdraw
->private;
353 pread
= __driFindDrawable(psp
->drawHash
, read
);
358 prp
= (__DRIdrawablePrivate
*)pread
->private;
361 /* Let driver unbind drawable from context */
362 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
365 if (pdp
->refcount
== 0) {
373 if (prp
->refcount
== 0) {
382 /* XXX this is disabled so that if we call SwapBuffers on an unbound
383 * window we can determine the last context bound to the window and
384 * use that context's lock. (BrianP, 2-Dec-2000)
387 /* Unbind the drawable */
388 pcp
->driDrawablePriv
= NULL
;
389 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
397 * This function takes both a read buffer and a draw buffer. This is needed
398 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
401 * \bug This function calls \c driCreateNewDrawable in two places with the
402 * \c renderType hard-coded to \c GLX_WINDOW_BIT. Some checking might
403 * be needed in those places when support for pbuffers and / or pixmaps
404 * is added. Is it safe to assume that the drawable is a window?
406 static Bool
driBindContext2(Display
*dpy
, int scrn
,
407 GLXDrawable draw
, GLXDrawable read
,
410 __DRIscreen
*pDRIScreen
;
411 __DRIdrawable
*pdraw
;
412 __DRIdrawablePrivate
*pdp
;
413 __DRIdrawable
*pread
;
414 __DRIdrawablePrivate
*prp
;
415 __DRIscreenPrivate
*psp
;
416 __DRIcontextPrivate
*pcp
;
417 const __GLcontextModes
*modes
;
420 ** Assume error checking is done properly in glXMakeCurrent before
421 ** calling driBindContext.
424 if (gc
== NULL
|| draw
== None
|| read
== None
) {
429 pDRIScreen
= __glXFindDRIScreen(dpy
, scrn
);
430 #ifdef DRI_NEW_INTERFACE_ONLY
431 if ( (pDRIScreen
== NULL
) || (pDRIScreen
->private == NULL
) ) {
436 if ( driCompareGLXAPIVersion( 20031201 ) >= 0 ) {
437 #endif /* DRI_NEW_INTERFACE_ONLY */
439 #ifndef DRI_NEW_INTERFACE_ONLY
442 modes
= findConfigMode( dpy
, scrn
, gc
->vid
, pDRIScreen
);
443 if ( modes
== NULL
) {
450 /* findConfigMode will return NULL if the DRI screen or screen private
453 assert( (pDRIScreen
!= NULL
) && (pDRIScreen
->private != NULL
) );
454 #endif /* DRI_NEW_INTERFACE_ONLY */
457 /* Find the _DRIdrawable which corresponds to the writing GLXDrawable */
458 psp
= (__DRIscreenPrivate
*)pDRIScreen
->private;
459 pdraw
= __driFindDrawable(psp
->drawHash
, draw
);
461 /* Allocate a new drawable */
462 pdraw
= (__DRIdrawable
*)Xmalloc(sizeof(__DRIdrawable
));
468 /* Create a new drawable */
469 driCreateNewDrawable(dpy
, modes
, draw
, pdraw
, GLX_WINDOW_BIT
,
470 empty_attribute_list
);
471 if (!pdraw
->private) {
478 pdp
= (__DRIdrawablePrivate
*) pdraw
->private;
480 /* Find the _DRIdrawable which corresponds to the reading GLXDrawable */
482 /* read buffer == draw buffer */
486 pread
= __driFindDrawable(psp
->drawHash
, read
);
488 /* Allocate a new drawable */
489 pread
= (__DRIdrawable
*)Xmalloc(sizeof(__DRIdrawable
));
495 /* Create a new drawable */
496 driCreateNewDrawable(dpy
, modes
, read
, pread
, GLX_WINDOW_BIT
,
497 empty_attribute_list
);
498 if (!pread
->private) {
504 prp
= (__DRIdrawablePrivate
*) pread
->private;
507 /* Bind the drawable to the context */
508 pcp
= (__DRIcontextPrivate
*)gc
->driContext
.private;
509 pcp
->driDrawablePriv
= pdp
;
510 pdp
->driContextPriv
= pcp
;
517 ** Now that we have a context associated with this drawable, we can
518 ** initialize the drawable information if has not been done before.
520 if (!pdp
->pStamp
|| *pdp
->pStamp
!= pdp
->lastStamp
) {
521 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
522 __driUtilUpdateDrawableInfo(pdp
);
523 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
526 /* Call device-specific MakeCurrent */
527 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
534 * Simply call bind with the same GLXDrawable for the read and draw buffers.
536 static Bool
driBindContext(Display
*dpy
, int scrn
,
537 GLXDrawable draw
, GLXContext gc
)
539 return driBindContext2(dpy
, scrn
, draw
, draw
, gc
);
544 * Simply call bind with the same GLXDrawable for the read and draw buffers.
546 static Bool
driUnbindContext(Display
*dpy
, int scrn
,
547 GLXDrawable draw
, GLXContext gc
,
551 return driUnbindContext2( dpy
, scrn
, draw
, draw
, gc
);
557 /*****************************************************************/
558 /** \name Drawable handling functions */
559 /*****************************************************************/
563 * Update private drawable information.
565 * \param pdp pointer to the private drawable information to update.
567 * This function basically updates the __DRIdrawablePrivate struct's
568 * cliprect information by calling \c __DRIDrawablePrivate::getInfo. This is
569 * usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
570 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
571 * the values are different that means we have to update the clipping
575 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
577 __DRIscreenPrivate
*psp
;
578 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
580 if (!pcp
|| (pdp
!= pcp
->driDrawablePriv
)) {
585 psp
= pdp
->driScreenPriv
;
591 if (pdp
->pClipRects
) {
592 Xfree(pdp
->pClipRects
);
595 if (pdp
->pBackClipRects
) {
596 Xfree(pdp
->pBackClipRects
);
599 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
601 if (!__driFindDrawable(psp
->drawHash
, pdp
->draw
) ||
602 ! (*pdp
->getInfo
)(pdp
->display
, pdp
->screen
, pdp
->draw
,
603 &pdp
->index
, &pdp
->lastStamp
,
604 &pdp
->x
, &pdp
->y
, &pdp
->w
, &pdp
->h
,
605 &pdp
->numClipRects
, &pdp
->pClipRects
,
608 &pdp
->numBackClipRects
,
609 &pdp
->pBackClipRects
)) {
610 /* Error -- eg the window may have been destroyed. Keep going
613 pdp
->pStamp
= &pdp
->lastStamp
; /* prevent endless loop */
614 pdp
->numClipRects
= 0;
615 pdp
->pClipRects
= NULL
;
616 pdp
->numBackClipRects
= 0;
617 pdp
->pBackClipRects
= NULL
;
620 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
622 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
628 /*****************************************************************/
629 /** \name GLX callbacks */
630 /*****************************************************************/
636 * \param dpy the display handle.
637 * \param drawablePrivate opaque pointer to the per-drawable private info.
640 * This function calls __DRIdrawablePrivate::swapBuffers.
642 * Is called directly from glXSwapBuffers().
644 static void driSwapBuffers( Display
*dpy
, void *drawablePrivate
)
646 __DRIdrawablePrivate
*dPriv
= (__DRIdrawablePrivate
*) drawablePrivate
;
647 dPriv
->swapBuffers(dPriv
);
652 * Called directly from a number of higher-level GLX functions.
654 static int driGetMSC( void *screenPrivate
, int64_t *msc
)
656 __DRIscreenPrivate
*sPriv
= (__DRIscreenPrivate
*) screenPrivate
;
658 return sPriv
->DriverAPI
.GetMSC( sPriv
, msc
);
662 * Called directly from a number of higher-level GLX functions.
664 static int driGetSBC( Display
*dpy
, void *drawablePrivate
, int64_t *sbc
)
666 __DRIdrawablePrivate
*dPriv
= (__DRIdrawablePrivate
*) drawablePrivate
;
671 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
672 *sbc
= sInfo
.swap_count
;
677 static int driWaitForSBC( Display
* dpy
, void *drawablePriv
,
679 int64_t * msc
, int64_t * sbc
)
681 __DRIdrawablePrivate
*dPriv
= (__DRIdrawablePrivate
*) drawablePriv
;
683 return dPriv
->driScreenPriv
->DriverAPI
.WaitForSBC( dPriv
, target_sbc
,
687 static int driWaitForMSC( Display
* dpy
, void *drawablePriv
,
689 int64_t divisor
, int64_t remainder
,
690 int64_t * msc
, int64_t * sbc
)
692 __DRIdrawablePrivate
*dPriv
= (__DRIdrawablePrivate
*) drawablePriv
;
697 status
= dPriv
->driScreenPriv
->DriverAPI
.WaitForMSC( dPriv
, target_msc
,
701 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
702 * is supported but GLX_OML_sync_control is not. Therefore, don't return
703 * an error value if GetSwapInfo() is not implemented.
706 && dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo
) {
707 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
708 *sbc
= sInfo
.swap_count
;
714 static int64_t driSwapBuffersMSC( Display
* dpy
, void *drawablePriv
,
716 int64_t divisor
, int64_t remainder
)
718 __DRIdrawablePrivate
*dPriv
= (__DRIdrawablePrivate
*) drawablePriv
;
720 return dPriv
->driScreenPriv
->DriverAPI
.SwapBuffersMSC( dPriv
, target_msc
,
727 * This is called via __DRIscreenRec's createNewDrawable pointer.
729 static void *driCreateNewDrawable(Display
*dpy
,
730 const __GLcontextModes
*modes
,
732 __DRIdrawable
*pdraw
,
736 __DRIscreen
* const pDRIScreen
= __glXFindDRIScreen(dpy
, modes
->screen
);
737 __DRIscreenPrivate
*psp
;
738 __DRIdrawablePrivate
*pdp
;
741 /* Since pbuffers are not yet supported, no drawable attributes are
746 if ( (pDRIScreen
== NULL
) || (pDRIScreen
->private == NULL
) ) {
750 pdp
= (__DRIdrawablePrivate
*)Xmalloc(sizeof(__DRIdrawablePrivate
));
755 if (!XF86DRICreateDrawable(dpy
, modes
->screen
, draw
, &pdp
->hHWDrawable
)) {
770 pdp
->numClipRects
= 0;
771 pdp
->numBackClipRects
= 0;
772 pdp
->pClipRects
= NULL
;
773 pdp
->pBackClipRects
= NULL
;
775 pdp
->screen
= modes
->screen
;
777 psp
= (__DRIscreenPrivate
*)pDRIScreen
->private;
778 pdp
->driScreenPriv
= psp
;
779 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
781 pdp
->getInfo
= (GetDrawableInfo
*)
782 glXGetProcAddress( (const GLubyte
*) "__glXGetDrawableInfo" );
783 if ( pdp
->getInfo
== NULL
) {
784 pdp
->getInfo
= XF86DRIGetDrawableInfo
;
787 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, modes
,
788 renderType
== GLX_PIXMAP_BIT
)) {
789 (void)XF86DRIDestroyDrawable(dpy
, modes
->screen
, pdp
->draw
);
794 pdraw
->private = pdp
;
795 pdraw
->destroyDrawable
= driDestroyDrawable
;
796 pdraw
->swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
798 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
799 pdraw
->getSBC
= driGetSBC
;
800 pdraw
->waitForSBC
= driWaitForSBC
;
801 pdraw
->waitForMSC
= driWaitForMSC
;
802 pdraw
->swapBuffersMSC
= driSwapBuffersMSC
;
803 pdraw
->frameTracking
= NULL
;
804 pdraw
->queryFrameTracking
= driQueryFrameTracking
;
806 /* This special default value is replaced with the configured
807 * default value when the drawable is first bound to a direct
808 * rendering context. */
809 pdraw
->swap_interval
= (unsigned)-1;
812 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
814 /* Add pdraw to drawable list */
815 if (!__driAddDrawable(psp
->drawHash
, pdraw
)) {
817 (*pdraw
->destroyDrawable
)(dpy
, pdp
);
820 pdraw
->private = NULL
;
826 static __DRIdrawable
*driGetDrawable(Display
*dpy
, GLXDrawable draw
,
829 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*) screenPrivate
;
832 ** Make sure this routine returns NULL if the drawable is not bound
833 ** to a direct rendering context!
835 return __driFindDrawable(psp
->drawHash
, draw
);
838 static void driDestroyDrawable(Display
*dpy
, void *drawablePrivate
)
840 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*) drawablePrivate
;
841 __DRIscreenPrivate
*psp
= pdp
->driScreenPriv
;
842 int scrn
= psp
->myNum
;
845 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
846 if ((*window_exists
)(dpy
, pdp
->draw
))
847 (void)XF86DRIDestroyDrawable(dpy
, scrn
, pdp
->draw
);
848 if (pdp
->pClipRects
) {
849 Xfree(pdp
->pClipRects
);
850 pdp
->pClipRects
= NULL
;
852 if (pdp
->pBackClipRects
) {
853 Xfree(pdp
->pBackClipRects
);
854 pdp
->pBackClipRects
= NULL
;
863 /*****************************************************************/
864 /** \name Context handling functions */
865 /*****************************************************************/
869 * Destroy the per-context private information.
871 * \param dpy the display handle.
872 * \param scrn the screen number.
873 * \param contextPrivate opaque pointer to the per-drawable private info.
876 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
877 * drmDestroyContext(), and finally frees \p contextPrivate.
879 static void driDestroyContext(Display
*dpy
, int scrn
, void *contextPrivate
)
881 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*) contextPrivate
;
884 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
885 __driGarbageCollectDrawables(pcp
->driScreenPriv
->drawHash
);
886 (void)XF86DRIDestroyContext(dpy
, scrn
, pcp
->contextID
);
893 * Create the per-drawable private driver information.
895 * \param dpy The display handle.
896 * \param modes Mode used to create the new context.
897 * \param render_type Type of rendering target. \c GLX_RGBA is the only
898 * type likely to ever be supported for direct-rendering.
899 * \param sharedPrivate The shared context dependent methods or \c NULL if
901 * \param pctx DRI context to receive the context dependent methods.
903 * \returns An opaque pointer to the per-context private information on
904 * success, or \c NULL on failure.
907 * This function allocates and fills a __DRIcontextPrivateRec structure. It
908 * performs some device independent initialization and passes all the
909 * relevent information to __DriverAPIRec::CreateContext to create the
914 driCreateNewContext(Display
*dpy
, const __GLcontextModes
*modes
,
915 int render_type
, void *sharedPrivate
, __DRIcontext
*pctx
)
917 __DRIscreen
*pDRIScreen
;
918 __DRIcontextPrivate
*pcp
;
919 __DRIcontextPrivate
*pshare
= (__DRIcontextPrivate
*) sharedPrivate
;
920 __DRIscreenPrivate
*psp
;
921 void * const shareCtx
= (pshare
!= NULL
) ? pshare
->driverPrivate
: NULL
;
923 pDRIScreen
= __glXFindDRIScreen(dpy
, modes
->screen
);
924 if ( (pDRIScreen
== NULL
) || (pDRIScreen
->private == NULL
) ) {
929 psp
= (__DRIscreenPrivate
*)pDRIScreen
->private;
931 pcp
= (__DRIcontextPrivate
*)Xmalloc(sizeof(__DRIcontextPrivate
));
936 if (! (*create_context_with_config
)(dpy
, modes
->screen
, modes
->fbconfigID
,
937 &pcp
->contextID
, &pcp
->hHWContext
)) {
943 pcp
->driScreenPriv
= psp
;
944 pcp
->driDrawablePriv
= NULL
;
946 /* When the first context is created for a screen, initialize a "dummy"
950 if (!psp
->dummyContextPriv
.driScreenPriv
) {
951 psp
->dummyContextPriv
.contextID
= 0;
952 psp
->dummyContextPriv
.hHWContext
= psp
->pSAREA
->dummy_context
;
953 psp
->dummyContextPriv
.driScreenPriv
= psp
;
954 psp
->dummyContextPriv
.driDrawablePriv
= NULL
;
955 psp
->dummyContextPriv
.driverPrivate
= NULL
;
956 /* No other fields should be used! */
959 pctx
->destroyContext
= driDestroyContext
;
960 pctx
->bindContext
= driBindContext
;
961 pctx
->unbindContext
= driUnbindContext
;
962 if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) {
963 pctx
->bindContext2
= driBindContext2
;
964 pctx
->unbindContext2
= driUnbindContext2
;
967 if ( !(*psp
->DriverAPI
.CreateContext
)(modes
, pcp
, shareCtx
) ) {
968 (void)XF86DRIDestroyContext(dpy
, modes
->screen
, pcp
->contextID
);
973 __driGarbageCollectDrawables(pcp
->driScreenPriv
->drawHash
);
979 #ifndef DRI_NEW_INTERFACE_ONLY
981 * Create the per-drawable private driver information.
983 * \param dpy the display handle.
984 * \param vis the visual information.
985 * \param sharedPrivate the shared context dependent methods or \c NULL if
987 * \param pctx will receive the context dependent methods.
989 * \returns a opaque pointer to the per-context private information on success, or \c NULL
993 * This function has been replaced by \c driCreateNewContext. In drivers
994 * built to work with XFree86, this function will continue to exist to support
995 * older versions of libGL. Starting with the next major relelase of XFree86,
996 * this function will be removed.
999 * This function allocates and fills a __DRIcontextPrivateRec structure. It
1000 * gets the visual, converts it into a __GLcontextModesRec and passes it
1001 * to __DriverAPIRec::CreateContext to create the context.
1003 static void *driCreateContext(Display
*dpy
, XVisualInfo
*vis
,
1004 void *sharedPrivate
, __DRIcontext
*pctx
)
1006 __DRIscreen
*pDRIScreen
;
1007 const __GLcontextModes
*modes
;
1009 pDRIScreen
= __glXFindDRIScreen(dpy
, vis
->screen
);
1010 if ( (pDRIScreen
== NULL
) || (pDRIScreen
->private == NULL
) ) {
1016 /* Setup a __GLcontextModes struct corresponding to vis->visualid
1017 * and create the rendering context.
1020 modes
= findConfigMode(dpy
, vis
->screen
, vis
->visualid
, pDRIScreen
);
1021 return (modes
== NULL
)
1023 : driCreateNewContext( dpy
, modes
, GLX_RGBA_TYPE
,
1024 sharedPrivate
, pctx
);
1026 #endif /* DRI_NEW_INTERFACE_ONLY */
1031 /*****************************************************************/
1032 /** \name Screen handling functions */
1033 /*****************************************************************/
1037 * Destroy the per-screen private information.
1039 * \param dpy the display handle.
1040 * \param scrn the screen number.
1041 * \param screenPrivate opaque pointer to the per-screen private information.
1044 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
1045 * drmClose(), and finally frees \p screenPrivate.
1047 static void driDestroyScreen(Display
*dpy
, int scrn
, void *screenPrivate
)
1049 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*) screenPrivate
;
1052 /* No interaction with the X-server is possible at this point. This
1053 * routine is called after XCloseDisplay, so there is no protocol
1054 * stream open to the X-server anymore.
1057 if (psp
->DriverAPI
.DestroyScreen
)
1058 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
1060 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
1061 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
1062 Xfree(psp
->pDevPriv
);
1063 (void)drmClose(psp
->fd
);
1064 if ( psp
->modes
!= NULL
) {
1065 _gl_context_modes_destroy( psp
->modes
);
1073 * Utility function used to create a new driver-private screen structure.
1075 * \param dpy Display pointer
1076 * \param scrn Index of the screen
1077 * \param psc DRI screen data (not driver private)
1078 * \param modes Linked list of known display modes. This list is, at a
1079 * minimum, a list of modes based on the current display mode.
1080 * These roughly match the set of available X11 visuals, but it
1081 * need not be limited to X11! The calling libGL should create
1082 * a list that will inform the driver of the current display
1083 * mode (i.e., color buffer depth, depth buffer depth, etc.).
1084 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
1086 * \param dri_version Version of the "server-side" DRI.
1087 * \param drm_version Version of the kernel DRM.
1088 * \param frame_buffer Data describing the location and layout of the
1090 * \param pSAREA Pointer the the SAREA.
1091 * \param fd Device handle for the DRM.
1092 * \param internal_api_version Version of the internal interface between the
1094 * \param driverAPI Driver API functions used by other routines in dri_util.c.
1096 __DRIscreenPrivate
*
1097 __driUtilCreateNewScreen(Display
*dpy
, int scrn
, __DRIscreen
*psc
,
1098 __GLcontextModes
* modes
,
1099 const __DRIversion
* ddx_version
,
1100 const __DRIversion
* dri_version
,
1101 const __DRIversion
* drm_version
,
1102 const __DRIframebuffer
* frame_buffer
,
1105 int internal_api_version
,
1106 const struct __DriverAPIRec
*driverAPI
)
1108 __DRIscreenPrivate
*psp
;
1111 window_exists
= (PFNGLXWINDOWEXISTSPROC
)
1112 glXGetProcAddress( (const GLubyte
*) "__glXWindowExists" );
1114 if ( window_exists
== NULL
) {
1115 #ifdef DRI_NEW_INTERFACE_ONLY
1116 fprintf( stderr
, "libGL error: libGL.so version (%08u) is too old. "
1117 "20021128 or later is required.\n", internal_api_version
);
1120 window_exists
= (PFNGLXWINDOWEXISTSPROC
) __driWindowExists
;
1121 #endif /* DRI_NEW_INTERFACE_ONLY */
1124 create_context_with_config
= (PFNGLXCREATECONTEXTWITHCONFIGPROC
)
1125 glXGetProcAddress( (const GLubyte
*) "__glXCreateContextWithConfig" );
1126 if ( create_context_with_config
== NULL
) {
1127 #ifdef DRI_NEW_INTERFACE_ONLY
1128 fprintf( stderr
, "libGL error: libGL.so version (%08u) is too old. "
1129 "20031201 or later is required.\n", internal_api_version
);
1132 create_context_with_config
= (PFNGLXCREATECONTEXTWITHCONFIGPROC
)
1133 fake_XF86DRICreateContextWithConfig
;
1134 #endif /* DRI_NEW_INTERFACE_ONLY */
1137 api_ver
= internal_api_version
;
1139 psp
= (__DRIscreenPrivate
*)Xmalloc(sizeof(__DRIscreenPrivate
));
1144 /* Create the hash table */
1145 psp
->drawHash
= drmHashCreate();
1146 if ( psp
->drawHash
== NULL
) {
1157 ** NOT_DONE: This is used by the X server to detect when the client
1158 ** has died while holding the drawable lock. The client sets the
1159 ** drawable lock to this value.
1161 psp
->drawLockID
= 1;
1163 psp
->drmMajor
= drm_version
->major
;
1164 psp
->drmMinor
= drm_version
->minor
;
1165 psp
->drmPatch
= drm_version
->patch
;
1166 psp
->ddxMajor
= ddx_version
->major
;
1167 psp
->ddxMinor
= ddx_version
->minor
;
1168 psp
->ddxPatch
= ddx_version
->patch
;
1169 psp
->driMajor
= dri_version
->major
;
1170 psp
->driMinor
= dri_version
->minor
;
1171 psp
->driPatch
= dri_version
->patch
;
1173 /* install driver's callback functions */
1174 memcpy( &psp
->DriverAPI
, driverAPI
, sizeof(struct __DriverAPIRec
) );
1176 psp
->pSAREA
= pSAREA
;
1178 psp
->pFB
= frame_buffer
->base
;
1179 psp
->fbSize
= frame_buffer
->size
;
1180 psp
->fbStride
= frame_buffer
->stride
;
1181 psp
->fbWidth
= frame_buffer
->width
;
1182 psp
->fbHeight
= frame_buffer
->height
;
1183 psp
->devPrivSize
= frame_buffer
->dev_priv_size
;
1184 psp
->pDevPriv
= frame_buffer
->dev_priv
;
1189 ** Do not init dummy context here; actual initialization will be
1190 ** done when the first DRI context is created. Init screen priv ptr
1191 ** to NULL to let CreateContext routine that it needs to be inited.
1193 psp
->dummyContextPriv
.driScreenPriv
= NULL
;
1195 psc
->destroyScreen
= driDestroyScreen
;
1196 #ifndef DRI_NEW_INTERFACE_ONLY
1197 psc
->createContext
= driCreateContext
;
1199 psc
->createConteext
= NULL
;
1201 psc
->createNewDrawable
= driCreateNewDrawable
;
1202 psc
->getDrawable
= driGetDrawable
;
1203 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
1204 psc
->getMSC
= driGetMSC
;
1206 if ( driCompareGLXAPIVersion( 20030824 ) >= 0 ) {
1207 psc
->createNewContext
= driCreateNewContext
;
1211 if ( (psp
->DriverAPI
.InitDriver
!= NULL
)
1212 && !(*psp
->DriverAPI
.InitDriver
)(psp
) ) {
1222 #ifndef DRI_NEW_INTERFACE_ONLY
1224 * Utility function used to create a new driver-private screen structure.
1226 * \param dpy Display pointer.
1227 * \param scrn Index of the screen.
1228 * \param psc DRI screen data (not driver private)
1229 * \param numConfigs Number of visual configs pointed to by \c configs.
1230 * \param configs Array of GLXvisualConfigs exported by the 2D driver.
1231 * \param driverAPI Driver API functions used by other routines in dri_util.c.
1234 * This function has been replaced by \c __driUtilCreateNewScreen. In drivers
1235 * built to work with XFree86, this function will continue to exist to support
1236 * older versions of libGL. Starting with the next major relelase of XFree86,
1237 * this function will be removed.
1239 __DRIscreenPrivate
*
1240 __driUtilCreateScreen(Display
*dpy
, int scrn
, __DRIscreen
*psc
,
1241 int numConfigs
, __GLXvisualConfig
*configs
,
1242 const struct __DriverAPIRec
*driverAPI
)
1245 __DRIscreenPrivate
*psp
= NULL
;
1249 __GLcontextModes
*modes
;
1250 __GLcontextModes
*temp
;
1252 __DRIversion ddx_version
;
1253 __DRIversion dri_version
;
1254 __DRIversion drm_version
;
1255 __DRIframebuffer framebuffer
;
1258 const char * err_msg
;
1259 const char * err_extra
;
1262 if (!XF86DRIQueryDirectRenderingCapable(dpy
, scrn
, &directCapable
)
1263 || !directCapable
) {
1268 /* Create the linked list of context modes, and populate it with the
1269 * GLX visual information passed in by libGL.
1272 modes
= _gl_context_modes_create( numConfigs
, sizeof(__GLcontextModes
) );
1273 if ( modes
== NULL
) {
1278 for ( i
= 0 ; i
< numConfigs
; i
++ ) {
1279 assert( temp
!= NULL
);
1280 _gl_copy_visual_to_context_mode( temp
, & configs
[i
] );
1281 temp
->screen
= scrn
;
1286 err_msg
= "XF86DRIOpenConnection";
1289 if (XF86DRIOpenConnection(dpy
, scrn
, &hSAREA
, &BusID
)) {
1290 fd
= drmOpen(NULL
,BusID
);
1291 Xfree(BusID
); /* No longer needed */
1293 err_msg
= "open DRM";
1294 err_extra
= strerror( -fd
);
1299 err_msg
= "drmGetMagic";
1302 if (!drmGetMagic(fd
, &magic
)) {
1303 drmVersionPtr version
= drmGetVersion(fd
);
1305 drm_version
.major
= version
->version_major
;
1306 drm_version
.minor
= version
->version_minor
;
1307 drm_version
.patch
= version
->version_patchlevel
;
1308 drmFreeVersion(version
);
1311 drm_version
.major
= -1;
1312 drm_version
.minor
= -1;
1313 drm_version
.patch
= -1;
1316 err_msg
= "XF86DRIAuthConnection";
1317 if (XF86DRIAuthConnection(dpy
, scrn
, magic
)) {
1321 * Get device name (like "tdfx") and the ddx version numbers.
1322 * We'll check the version in each DRI driver's "createScreen"
1325 err_msg
= "XF86DRIGetClientDriverName";
1326 if (XF86DRIGetClientDriverName(dpy
, scrn
,
1332 /* No longer needed. */
1333 Xfree( driverName
);
1336 * Get the DRI X extension version.
1338 err_msg
= "XF86DRIQueryVersion";
1339 if (XF86DRIQueryVersion(dpy
,
1342 &dri_version
.patch
)) {
1347 * Get device-specific info. pDevPriv will point to a struct
1348 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
1349 * that has information about the screen size, depth, pitch,
1350 * ancilliary buffers, DRM mmap handles, etc.
1352 err_msg
= "XF86DRIGetDeviceInfo";
1353 if (XF86DRIGetDeviceInfo(dpy
, scrn
,
1357 &framebuffer
.stride
,
1358 &framebuffer
.dev_priv_size
,
1359 &framebuffer
.dev_priv
)) {
1360 framebuffer
.width
= DisplayWidth(dpy
, scrn
);
1361 framebuffer
.height
= DisplayHeight(dpy
, scrn
);
1364 * Map the framebuffer region.
1366 status
= drmMap(fd
, hFB
, framebuffer
.size
,
1367 (drmAddressPtr
)&framebuffer
.base
);
1369 err_msg
= "drmMap of framebuffer";
1370 err_extra
= strerror( -status
);
1372 if ( status
== 0 ) {
1374 * Map the SAREA region. Further mmap regions may be setup in
1375 * each DRI driver's "createScreen" function.
1377 status
= drmMap(fd
, hSAREA
, SAREA_MAX
,
1380 err_msg
= "drmMap of sarea";
1381 err_extra
= strerror( -status
);
1383 if ( status
== 0 ) {
1384 PFNGLXGETINTERNALVERSIONPROC get_ver
;
1386 get_ver
= (PFNGLXGETINTERNALVERSIONPROC
)
1387 glXGetProcAddress( (const GLubyte
*) "__glXGetInternalVersion" );
1389 err_msg
= "InitDriver";
1391 psp
= __driUtilCreateNewScreen( dpy
, scrn
, psc
, modes
,
1398 (get_ver
!= NULL
) ? (*get_ver
)() : 1,
1410 if ( psp
== NULL
) {
1411 if ( pSAREA
!= MAP_FAILED
) {
1412 (void)drmUnmap(pSAREA
, SAREA_MAX
);
1415 if ( framebuffer
.base
!= MAP_FAILED
) {
1416 (void)drmUnmap((drmAddress
)framebuffer
.base
, framebuffer
.size
);
1419 if ( framebuffer
.dev_priv
!= NULL
) {
1420 Xfree(framebuffer
.dev_priv
);
1427 if ( modes
!= NULL
) {
1428 _gl_context_modes_destroy( modes
);
1431 (void)XF86DRICloseConnection(dpy
, scrn
);
1433 if ( err_extra
!= NULL
) {
1434 fprintf(stderr
, "libGL error: %s failed (%s)\n", err_msg
,
1438 fprintf(stderr
, "libGL error: %s failed\n", err_msg
);
1441 fprintf(stderr
, "libGL error: reverting to (slow) indirect rendering\n");
1446 #endif /* DRI_NEW_INTERFACE_ONLY */
1450 * Compare the current GLX API version with a driver supplied required version.
1452 * The minimum required version is compared with the API version exported by
1453 * the \c __glXGetInternalVersion function (in libGL.so).
1455 * \param required_version Minimum required internal GLX API version.
1456 * \return A tri-value return, as from strcmp is returned. A value less
1457 * than, equal to, or greater than zero will be returned if the
1458 * internal GLX API version is less than, equal to, or greater
1459 * than \c required_version.
1461 * \sa __glXGetInternalVersion().
1463 int driCompareGLXAPIVersion( GLuint required_version
)
1465 if ( api_ver
> required_version
) {
1468 else if ( api_ver
== required_version
) {
1477 driQueryFrameTracking( Display
* dpy
, void * priv
,
1478 int64_t * sbc
, int64_t * missedFrames
,
1479 float * lastMissedUsage
, float * usage
)
1481 static PFNGLXGETUSTPROC get_ust
;
1482 __DRIswapInfo sInfo
;
1485 __DRIdrawablePrivate
* dpriv
= (__DRIdrawablePrivate
*) priv
;
1487 if ( get_ust
== NULL
) {
1488 get_ust
= (PFNGLXGETUSTPROC
) glXGetProcAddress( (const GLubyte
*) "__glXGetUST" );
1491 status
= dpriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dpriv
, & sInfo
);
1492 if ( status
== 0 ) {
1493 *sbc
= sInfo
.swap_count
;
1494 *missedFrames
= sInfo
.swap_missed_count
;
1495 *lastMissedUsage
= sInfo
.swap_missed_usage
;
1497 (*get_ust
)( & ust
);
1498 *usage
= driCalculateSwapUsage( dpriv
, sInfo
.swap_ust
, ust
);
1506 * Calculate amount of swap interval used between GLX buffer swaps.
1508 * The usage value, on the range [0,max], is the fraction of total swap
1509 * interval time used between GLX buffer swaps is calculated.
1511 * \f$p = t_d / (i * t_r)\f$
1513 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
1514 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
1515 * required for a single vertical refresh period (as returned by \c
1516 * glXGetMscRateOML).
1518 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
1521 * \param dPriv Pointer to the private drawable structure.
1522 * \return If less than a single swap interval time period was required
1523 * between GLX buffer swaps, a number greater than 0 and less than
1524 * 1.0 is returned. If exactly one swap interval time period is
1525 * required, 1.0 is returned, and if more than one is required then
1526 * a number greater than 1.0 will be returned.
1528 * \sa glXSwapIntervalSGI glXGetMscRateOML
1530 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
1531 * be possible to cache the sync rate?
1534 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
1535 int64_t current_ust
)
1537 static PFNGLXGETMSCRATEOMLPROC get_msc_rate
= NULL
;
1544 if ( get_msc_rate
== NULL
) {
1545 get_msc_rate
= (PFNGLXGETMSCRATEOMLPROC
)
1546 glXGetProcAddress( (const GLubyte
*) "glXGetMscRateOML" );
1549 if ( (get_msc_rate
!= NULL
)
1550 && get_msc_rate( dPriv
->display
, dPriv
->draw
, &n
, &d
) ) {
1551 interval
= (dPriv
->pdraw
->swap_interval
!= 0)
1552 ? dPriv
->pdraw
->swap_interval
: 1;
1555 /* We want to calculate
1556 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
1557 * current_UST by calling __glXGetUST. last_swap_UST is stored in
1558 * dPriv->swap_ust. interval has already been calculated.
1560 * The only tricky part is us_per_refresh. us_per_refresh is
1561 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
1562 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
1563 * the denominator of the final calculation, we calculate
1564 * (interval * 1000000 * d) and move n into the numerator.
1567 usage
= (current_ust
- last_swap_ust
);
1569 usage
/= (interval
* d
);
1578 #endif /* GLX_DIRECT_RENDERING */