summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/common/dri_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/common/dri_util.c')
-rw-r--r--src/mesa/drivers/dri/common/dri_util.c1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c
new file mode 100644
index 0000000000..03d92c02f2
--- /dev/null
+++ b/src/mesa/drivers/dri/common/dri_util.c
@@ -0,0 +1,1654 @@
+/* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
+/**
+ * \file dri_util.c
+ * DRI utility functions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * \note
+ * When \c DRI_NEW_INTERFACE_ONLY is defined, code is built / not built so
+ * that only the "new" libGL-to-driver interfaces are supported. This breaks
+ * backwards compatability. However, this may be necessary when DRI drivers
+ * are built to be used in non-XFree86 environments.
+ *
+ * \todo There are still some places in the code that need to be wrapped with
+ * \c DRI_NEW_INTERFACE_ONLY.
+ */
+
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <inttypes.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <X11/Xlibint.h>
+#include <Xext.h>
+#include <extutil.h>
+#include <stdio.h>
+#include "dri_util.h"
+#include "xf86dri.h"
+#include "sarea.h"
+#include "glcontextmodes.h"
+
+/*#define DRI_NEW_INTERFACE_ONLY*/
+
+/**
+ * This is used in a couple of places that call \c driCreateNewDrawable.
+ */
+static const int empty_attribute_list[1] = { None };
+
+/**
+ * Function used to determine if a drawable (window) still exists. Ideally
+ * this function comes from libGL. With older versions of libGL from XFree86
+ * we can fall-back to an internal version.
+ *
+ * \sa __driWindowExists __glXWindowExists
+ */
+static PFNGLXWINDOWEXISTSPROC window_exists;
+
+typedef Bool (*PFNGLXCREATECONTEXTWITHCONFIGPROC)( Display*, int, int, void *,
+ drmContextPtr );
+
+static PFNGLXCREATECONTEXTWITHCONFIGPROC create_context_with_config;
+
+/**
+ * Cached copy of the internal API version used by libGL and the client-side
+ * DRI driver.
+ */
+static int api_ver = 0;
+
+/* forward declarations */
+static int driQueryFrameTracking( Display * dpy, void * priv,
+ int64_t * sbc, int64_t * missedFrames, float * lastMissedUsage,
+ float * usage );
+
+static void *driCreateNewDrawable(Display *dpy, const __GLcontextModes *modes,
+ GLXDrawable draw, __DRIdrawable *pdraw, int renderType, const int *attrs);
+
+static void driDestroyDrawable(Display *dpy, void *drawablePrivate);
+
+
+
+
+#ifdef not_defined
+static Bool driFeatureOn(const char *name)
+{
+ char *env = getenv(name);
+
+ if (!env) return GL_FALSE;
+ if (!strcasecmp(env, "enable")) return GL_TRUE;
+ if (!strcasecmp(env, "1")) return GL_TRUE;
+ if (!strcasecmp(env, "on")) return GL_TRUE;
+ if (!strcasecmp(env, "true")) return GL_TRUE;
+ if (!strcasecmp(env, "t")) return GL_TRUE;
+ if (!strcasecmp(env, "yes")) return GL_TRUE;
+ if (!strcasecmp(env, "y")) return GL_TRUE;
+
+ return GL_FALSE;
+}
+#endif /* not_defined */
+
+
+/**
+ * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
+ * is set.
+ *
+ * Is called from the drivers.
+ *
+ * \param f \c printf like format string.
+ */
+void
+__driUtilMessage(const char *f, ...)
+{
+ va_list args;
+
+ if (getenv("LIBGL_DEBUG")) {
+ fprintf(stderr, "libGL error: \n");
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+
+/*****************************************************************/
+/** \name Visual utility functions */
+/*****************************************************************/
+/*@{*/
+
+#ifndef DRI_NEW_INTERFACE_ONLY
+/**
+ * Find a \c __GLcontextModes structure matching the given visual ID.
+ *
+ * \param dpy Display to search for a matching configuration.
+ * \param scrn Screen number on \c dpy to be searched.
+ * \param vid Desired \c VisualID to find.
+ *
+ * \returns A pointer to a \c __GLcontextModes structure that matches \c vid,
+ * if found, or \c NULL if no match is found.
+ */
+static const __GLcontextModes *
+findConfigMode(Display *dpy, int scrn, VisualID vid,
+ const __DRIscreen * pDRIScreen)
+{
+ if ( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) ) {
+ const __DRIscreenPrivate * const psp =
+ (const __DRIscreenPrivate *) pDRIScreen->private;
+
+ return _gl_context_modes_find_visual( psp->modes, vid );
+ }
+
+ return NULL;
+}
+
+
+/**
+ * This function is a hack to work-around old versions of libGL.so that
+ * do not export \c XF86DRICreateContextWithConfig. I would modify the
+ * code to just use this function, but the stand-alone driver (i.e., DRI
+ * drivers that are built to work without XFree86) shouldn't have to know
+ * about X structures like a \c Visual.
+ */
+static Bool
+fake_XF86DRICreateContextWithConfig( Display* dpy, int screen, int configID,
+ XID* context, drmContextPtr hHWContext )
+{
+ Visual vis;
+
+ vis.visualid = configID;
+ return XF86DRICreateContext( dpy, screen, & vis, context, hHWContext );
+}
+#endif /* DRI_NEW_INTERFACE_ONLY */
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Drawable list management */
+/*****************************************************************/
+/*@{*/
+
+static Bool __driAddDrawable(void *drawHash, __DRIdrawable *pdraw)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+
+ if (drmHashInsert(drawHash, pdp->draw, pdraw))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+static __DRIdrawable *__driFindDrawable(void *drawHash, GLXDrawable draw)
+{
+ int retcode;
+ __DRIdrawable *pdraw;
+
+ retcode = drmHashLookup(drawHash, draw, (void **)&pdraw);
+ if (retcode)
+ return NULL;
+
+ return pdraw;
+}
+
+static void __driRemoveDrawable(void *drawHash, __DRIdrawable *pdraw)
+{
+ int retcode;
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+
+ retcode = drmHashLookup(drawHash, pdp->draw, (void **)&pdraw);
+ if (!retcode) { /* Found */
+ drmHashDelete(drawHash, pdp->draw);
+ }
+}
+
+#ifndef DRI_NEW_INTERFACE_ONLY
+static Bool __driWindowExistsFlag;
+
+static int __driWindowExistsErrorHandler(Display *dpy, XErrorEvent *xerr)
+{
+ if (xerr->error_code == BadWindow) {
+ __driWindowExistsFlag = GL_FALSE;
+ }
+ return 0;
+}
+
+/**
+ * Determine if a window associated with a \c GLXDrawable exists on the
+ * X-server.
+ *
+ * \param dpy Display associated with the drawable to be queried.
+ * \param draw \c GLXDrawable to test.
+ *
+ * \returns \c GL_TRUE if a window exists that is associated with \c draw,
+ * otherwise \c GL_FALSE is returned.
+ *
+ * \warning This function is not currently thread-safe.
+ *
+ * \deprecated
+ * \c __glXWindowExists (from libGL) is prefered over this function. Starting
+ * with the next major release of XFree86, this function will be removed.
+ * Even now this function is no longer directly called. Instead it is called
+ * via a function pointer if and only if \c __glXWindowExists does not exist.
+ *
+ * \sa __glXWindowExists glXGetProcAddress window_exists
+ */
+static Bool __driWindowExists(Display *dpy, GLXDrawable draw)
+{
+ XWindowAttributes xwa;
+ int (*oldXErrorHandler)(Display *, XErrorEvent *);
+
+ XSync(dpy, GL_FALSE);
+ __driWindowExistsFlag = GL_TRUE;
+ oldXErrorHandler = XSetErrorHandler(__driWindowExistsErrorHandler);
+ XGetWindowAttributes(dpy, draw, &xwa); /* dummy request */
+ XSetErrorHandler(oldXErrorHandler);
+ return __driWindowExistsFlag;
+}
+#endif /* DRI_NEW_INTERFACE_ONLY */
+
+/**
+ * Find drawables in the local hash that have been destroyed on the
+ * server.
+ *
+ * \param drawHash Hash-table containing all know drawables.
+ */
+static void __driGarbageCollectDrawables(void *drawHash)
+{
+ GLXDrawable draw;
+ __DRIdrawable *pdraw;
+ Display *dpy;
+
+ if (drmHashFirst(drawHash, &draw, (void **)&pdraw)) {
+ do {
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
+ dpy = pdp->driScreenPriv->display;
+ if (! (*window_exists)(dpy, draw)) {
+ /* Destroy the local drawable data in the hash table, if the
+ drawable no longer exists in the Xserver */
+ __driRemoveDrawable(drawHash, pdraw);
+ (*pdraw->destroyDrawable)(dpy, pdraw->private);
+ Xfree(pdraw);
+ }
+ } while (drmHashNext(drawHash, &draw, (void **)&pdraw));
+ }
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context (un)binding functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Unbind context.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param draw drawable.
+ * \param read Current reading drawable.
+ * \param gc context.
+ *
+ * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::UnbindContext, and then decrements
+ * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
+ * return.
+ *
+ * While casting the opaque private pointers associated with the parameters
+ * into their respective real types it also assures they are not \c NULL.
+ */
+static Bool driUnbindContext3(Display *dpy, int scrn,
+ GLXDrawable draw, GLXDrawable read,
+ __DRIcontext *ctx)
+{
+ __DRIscreen *pDRIScreen;
+ __DRIdrawable *pdraw;
+ __DRIdrawable *pread;
+ __DRIcontextPrivate *pcp;
+ __DRIscreenPrivate *psp;
+ __DRIdrawablePrivate *pdp;
+ __DRIdrawablePrivate *prp;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driUnbindContext3.
+ */
+
+ if (ctx == NULL || draw == None || read == None) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ pDRIScreen = __glXFindDRIScreen(dpy, scrn);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ psp = (__DRIscreenPrivate *)pDRIScreen->private;
+ pcp = (__DRIcontextPrivate *)ctx->private;
+
+ pdraw = __driFindDrawable(psp->drawHash, draw);
+ if (!pdraw) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+ pdp = (__DRIdrawablePrivate *)pdraw->private;
+
+ pread = __driFindDrawable(psp->drawHash, read);
+ if (!pread) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+ prp = (__DRIdrawablePrivate *)pread->private;
+
+
+ /* Let driver unbind drawable from context */
+ (*psp->DriverAPI.UnbindContext)(pcp);
+
+
+ if (pdp->refcount == 0) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ pdp->refcount--;
+
+ if (prp != pdp) {
+ if (prp->refcount == 0) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ prp->refcount--;
+ }
+
+
+ /* XXX this is disabled so that if we call SwapBuffers on an unbound
+ * window we can determine the last context bound to the window and
+ * use that context's lock. (BrianP, 2-Dec-2000)
+ */
+#if 0
+ /* Unbind the drawable */
+ pcp->driDrawablePriv = NULL;
+ pdp->driContextPriv = &psp->dummyContextPriv;
+#endif
+
+ return GL_TRUE;
+}
+
+
+/**
+ * This function takes both a read buffer and a draw buffer. This is needed
+ * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
+ * function.
+ *
+ * \bug This function calls \c driCreateNewDrawable in two places with the
+ * \c renderType hard-coded to \c GLX_WINDOW_BIT. Some checking might
+ * be needed in those places when support for pbuffers and / or pixmaps
+ * is added. Is it safe to assume that the drawable is a window?
+ */
+static Bool DoBindContext(Display *dpy,
+ GLXDrawable draw, GLXDrawable read,
+ __DRIcontext *ctx, const __GLcontextModes * modes,
+ __DRIscreenPrivate *psp)
+{
+ __DRIdrawable *pdraw;
+ __DRIdrawablePrivate *pdp;
+ __DRIdrawable *pread;
+ __DRIdrawablePrivate *prp;
+ __DRIcontextPrivate * const pcp = ctx->private;
+
+
+ /* Find the _DRIdrawable which corresponds to the writing GLXDrawable */
+ pdraw = __driFindDrawable(psp->drawHash, draw);
+ if (!pdraw) {
+ /* Allocate a new drawable */
+ pdraw = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
+ if (!pdraw) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ /* Create a new drawable */
+ driCreateNewDrawable(dpy, modes, draw, pdraw, GLX_WINDOW_BIT,
+ empty_attribute_list);
+ if (!pdraw->private) {
+ /* ERROR!!! */
+ Xfree(pdraw);
+ return GL_FALSE;
+ }
+
+ }
+ pdp = (__DRIdrawablePrivate *) pdraw->private;
+
+ /* Find the _DRIdrawable which corresponds to the reading GLXDrawable */
+ if (read == draw) {
+ /* read buffer == draw buffer */
+ prp = pdp;
+ }
+ else {
+ pread = __driFindDrawable(psp->drawHash, read);
+ if (!pread) {
+ /* Allocate a new drawable */
+ pread = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
+ if (!pread) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ /* Create a new drawable */
+ driCreateNewDrawable(dpy, modes, read, pread, GLX_WINDOW_BIT,
+ empty_attribute_list);
+ if (!pread->private) {
+ /* ERROR!!! */
+ Xfree(pread);
+ return GL_FALSE;
+ }
+ }
+ prp = (__DRIdrawablePrivate *) pread->private;
+ }
+
+ /* Bind the drawable to the context */
+ pcp->driDrawablePriv = pdp;
+ pdp->driContextPriv = pcp;
+ pdp->refcount++;
+ if ( pdp != prp ) {
+ prp->refcount++;
+ }
+
+ /*
+ ** Now that we have a context associated with this drawable, we can
+ ** initialize the drawable information if has not been done before.
+ */
+ if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) {
+ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+ __driUtilUpdateDrawableInfo(pdp);
+ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+ }
+
+ /* Call device-specific MakeCurrent */
+ (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
+
+ return GL_TRUE;
+}
+
+
+/**
+ * This function takes both a read buffer and a draw buffer. This is needed
+ * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
+ * function.
+ */
+static Bool driBindContext3(Display *dpy, int scrn,
+ GLXDrawable draw, GLXDrawable read,
+ __DRIcontext * ctx)
+{
+ __DRIscreen *pDRIScreen;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driBindContext.
+ */
+
+ if (ctx == NULL || draw == None || read == None) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ pDRIScreen = __glXFindDRIScreen(dpy, scrn);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ return DoBindContext( dpy, draw, read, ctx, ctx->mode,
+ (__DRIscreenPrivate *)pDRIScreen->private );
+}
+
+
+#ifndef DRI_NEW_INTERFACE_ONLY
+/**
+ * This function takes both a read buffer and a draw buffer. This is needed
+ * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
+ * function.
+ */
+static Bool driBindContext2(Display *dpy, int scrn,
+ GLXDrawable draw, GLXDrawable read,
+ GLXContext gc)
+{
+ __DRIscreen *pDRIScreen;
+ const __GLcontextModes *modes;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driBindContext.
+ */
+
+ if (gc == NULL || draw == None || read == None) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ pDRIScreen = __glXFindDRIScreen(dpy, scrn);
+ modes = (driCompareGLXAPIVersion( 20040317 ) >= 0)
+ ? gc->driContext.mode
+ : findConfigMode( dpy, scrn, gc->vid, pDRIScreen );
+
+ if ( modes == NULL ) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ /* findConfigMode will return NULL if the DRI screen or screen private
+ * are NULL.
+ */
+ assert( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) );
+
+ return DoBindContext( dpy, draw, read, & gc->driContext, modes,
+ (__DRIscreenPrivate *)pDRIScreen->private );
+}
+
+static Bool driUnbindContext2(Display *dpy, int scrn,
+ GLXDrawable draw, GLXDrawable read,
+ GLXContext gc)
+{
+ return driUnbindContext3(dpy, scrn, draw, read, & gc->driContext);
+}
+
+/*
+ * Simply call bind with the same GLXDrawable for the read and draw buffers.
+ */
+static Bool driBindContext(Display *dpy, int scrn,
+ GLXDrawable draw, GLXContext gc)
+{
+ return driBindContext2(dpy, scrn, draw, draw, gc);
+}
+
+
+/*
+ * Simply call bind with the same GLXDrawable for the read and draw buffers.
+ */
+static Bool driUnbindContext(Display *dpy, int scrn,
+ GLXDrawable draw, GLXContext gc,
+ int will_rebind)
+{
+ (void) will_rebind;
+ return driUnbindContext2( dpy, scrn, draw, draw, gc );
+}
+#endif /* DRI_NEW_INTERFACE_ONLY */
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Drawable handling functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Update private drawable information.
+ *
+ * \param pdp pointer to the private drawable information to update.
+ *
+ * This function basically updates the __DRIdrawablePrivate struct's
+ * cliprect information by calling \c __DRIDrawablePrivate::getInfo. This is
+ * usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
+ * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
+ * the values are different that means we have to update the clipping
+ * info.
+ */
+void
+__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
+{
+ __DRIscreenPrivate *psp;
+ __DRIcontextPrivate *pcp = pdp->driContextPriv;
+
+ if (!pcp || (pdp != pcp->driDrawablePriv)) {
+ /* ERROR!!! */
+ return;
+ }
+
+ psp = pdp->driScreenPriv;
+ if (!psp) {
+ /* ERROR!!! */
+ return;
+ }
+
+ if (pdp->pClipRects) {
+ Xfree(pdp->pClipRects);
+ }
+
+ if (pdp->pBackClipRects) {
+ Xfree(pdp->pBackClipRects);
+ }
+
+ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+
+ if (!__driFindDrawable(psp->drawHash, pdp->draw) ||
+ ! (*pdp->getInfo)(pdp->display, pdp->screen, pdp->draw,
+ &pdp->index, &pdp->lastStamp,
+ &pdp->x, &pdp->y, &pdp->w, &pdp->h,
+ &pdp->numClipRects, &pdp->pClipRects,
+ &pdp->backX,
+ &pdp->backY,
+ &pdp->numBackClipRects,
+ &pdp->pBackClipRects )) {
+ /* Error -- eg the window may have been destroyed. Keep going
+ * with no cliprects.
+ */
+ pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
+ pdp->numClipRects = 0;
+ pdp->pClipRects = NULL;
+ pdp->numBackClipRects = 0;
+ pdp->pBackClipRects = NULL;
+ }
+ else
+ pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
+
+ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+
+}
+
+/*@}*/
+
+/*****************************************************************/
+/** \name GLX callbacks */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Swap buffers.
+ *
+ * \param dpy the display handle.
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DRIdrawablePrivate::swapBuffers.
+ *
+ * Is called directly from glXSwapBuffers().
+ */
+static void driSwapBuffers( Display *dpy, void *drawablePrivate )
+{
+ __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
+ dPriv->swapBuffers(dPriv);
+ (void) dpy;
+}
+
+/**
+ * Called directly from a number of higher-level GLX functions.
+ */
+static int driGetMSC( void *screenPrivate, int64_t *msc )
+{
+ __DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate;
+
+ return sPriv->DriverAPI.GetMSC( sPriv, msc );
+}
+
+/**
+ * Called directly from a number of higher-level GLX functions.
+ */
+static int driGetSBC( Display *dpy, void *drawablePrivate, int64_t *sbc )
+{
+ __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
+ __DRIswapInfo sInfo;
+ int status;
+
+
+ status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
+ *sbc = sInfo.swap_count;
+
+ return status;
+}
+
+static int driWaitForSBC( Display * dpy, void *drawablePriv,
+ int64_t target_sbc,
+ int64_t * msc, int64_t * sbc )
+{
+ __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
+
+ return dPriv->driScreenPriv->DriverAPI.WaitForSBC( dPriv, target_sbc,
+ msc, sbc );
+}
+
+static int driWaitForMSC( Display * dpy, void *drawablePriv,
+ int64_t target_msc,
+ int64_t divisor, int64_t remainder,
+ int64_t * msc, int64_t * sbc )
+{
+ __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
+ __DRIswapInfo sInfo;
+ int status;
+
+
+ status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
+ divisor, remainder,
+ msc );
+
+ /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
+ * is supported but GLX_OML_sync_control is not. Therefore, don't return
+ * an error value if GetSwapInfo() is not implemented.
+ */
+ if ( status == 0
+ && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
+ status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
+ *sbc = sInfo.swap_count;
+ }
+
+ return status;
+}
+
+static int64_t driSwapBuffersMSC( Display * dpy, void *drawablePriv,
+ int64_t target_msc,
+ int64_t divisor, int64_t remainder )
+{
+ __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
+
+ return dPriv->driScreenPriv->DriverAPI.SwapBuffersMSC( dPriv, target_msc,
+ divisor,
+ remainder );
+}
+
+
+/**
+ * This is called via __DRIscreenRec's createNewDrawable pointer.
+ */
+static void *driCreateNewDrawable(Display *dpy,
+ const __GLcontextModes *modes,
+ GLXDrawable draw,
+ __DRIdrawable *pdraw,
+ int renderType,
+ const int *attrs)
+{
+ __DRIscreen * const pDRIScreen = __glXFindDRIScreen(dpy, modes->screen);
+ __DRIscreenPrivate *psp;
+ __DRIdrawablePrivate *pdp;
+
+
+ /* Since pbuffers are not yet supported, no drawable attributes are
+ * supported either.
+ */
+ (void) attrs;
+
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return NULL;
+ }
+
+ pdp = (__DRIdrawablePrivate *)Xmalloc(sizeof(__DRIdrawablePrivate));
+ if (!pdp) {
+ return NULL;
+ }
+
+ if (!XF86DRICreateDrawable(dpy, modes->screen, draw, &pdp->hHWDrawable)) {
+ Xfree(pdp);
+ return NULL;
+ }
+
+ pdp->draw = draw;
+ pdp->pdraw = pdraw;
+ pdp->refcount = 0;
+ pdp->pStamp = NULL;
+ pdp->lastStamp = 0;
+ pdp->index = 0;
+ pdp->x = 0;
+ pdp->y = 0;
+ pdp->w = 0;
+ pdp->h = 0;
+ pdp->numClipRects = 0;
+ pdp->numBackClipRects = 0;
+ pdp->pClipRects = NULL;
+ pdp->pBackClipRects = NULL;
+ pdp->display = dpy;
+ pdp->screen = modes->screen;
+
+ psp = (__DRIscreenPrivate *)pDRIScreen->private;
+ pdp->driScreenPriv = psp;
+ pdp->driContextPriv = &psp->dummyContextPriv;
+
+ pdp->getInfo = (GetDrawableInfo *)
+ glXGetProcAddress( (const GLubyte *) "__glXGetDrawableInfo" );
+ if ( pdp->getInfo == NULL ) {
+ pdp->getInfo = XF86DRIGetDrawableInfo;
+ }
+
+ if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes,
+ renderType == GLX_PIXMAP_BIT)) {
+ (void)XF86DRIDestroyDrawable(dpy, modes->screen, pdp->draw);
+ Xfree(pdp);
+ return NULL;
+ }
+
+ pdraw->private = pdp;
+ pdraw->destroyDrawable = driDestroyDrawable;
+ pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
+
+ if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
+ pdraw->getSBC = driGetSBC;
+ pdraw->waitForSBC = driWaitForSBC;
+ pdraw->waitForMSC = driWaitForMSC;
+ pdraw->swapBuffersMSC = driSwapBuffersMSC;
+ pdraw->frameTracking = NULL;
+ pdraw->queryFrameTracking = driQueryFrameTracking;
+
+ /* This special default value is replaced with the configured
+ * default value when the drawable is first bound to a direct
+ * rendering context. */
+ pdraw->swap_interval = (unsigned)-1;
+ }
+
+ pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
+
+ /* Add pdraw to drawable list */
+ if (!__driAddDrawable(psp->drawHash, pdraw)) {
+ /* ERROR!!! */
+ (*pdraw->destroyDrawable)(dpy, pdp);
+ Xfree(pdp);
+ pdp = NULL;
+ pdraw->private = NULL;
+ }
+
+ return (void *) pdp;
+}
+
+static __DRIdrawable *driGetDrawable(Display *dpy, GLXDrawable draw,
+ void *screenPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
+
+ /*
+ ** Make sure this routine returns NULL if the drawable is not bound
+ ** to a direct rendering context!
+ */
+ return __driFindDrawable(psp->drawHash, draw);
+}
+
+static void driDestroyDrawable(Display *dpy, void *drawablePrivate)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawablePrivate;
+ __DRIscreenPrivate *psp = pdp->driScreenPriv;
+ int scrn = psp->myNum;
+
+ if (pdp) {
+ (*psp->DriverAPI.DestroyBuffer)(pdp);
+ if ((*window_exists)(dpy, pdp->draw))
+ (void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw);
+ if (pdp->pClipRects) {
+ Xfree(pdp->pClipRects);
+ pdp->pClipRects = NULL;
+ }
+ if (pdp->pBackClipRects) {
+ Xfree(pdp->pBackClipRects);
+ pdp->pBackClipRects = NULL;
+ }
+ Xfree(pdp);
+ }
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context handling functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Destroy the per-context private information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param contextPrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
+ * drmDestroyContext(), and finally frees \p contextPrivate.
+ */
+static void driDestroyContext(Display *dpy, int scrn, void *contextPrivate)
+{
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate;
+
+ if (pcp) {
+ (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
+ __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
+ (void)XF86DRIDestroyContext(dpy, scrn, pcp->contextID);
+ Xfree(pcp);
+ }
+}
+
+
+/**
+ * Create the per-drawable private driver information.
+ *
+ * \param dpy The display handle.
+ * \param modes Mode used to create the new context.
+ * \param render_type Type of rendering target. \c GLX_RGBA is the only
+ * type likely to ever be supported for direct-rendering.
+ * \param sharedPrivate The shared context dependent methods or \c NULL if
+ * non-existent.
+ * \param pctx DRI context to receive the context dependent methods.
+ *
+ * \returns An opaque pointer to the per-context private information on
+ * success, or \c NULL on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIcontextPrivateRec structure. It
+ * performs some device independent initialization and passes all the
+ * relevent information to __DriverAPIRec::CreateContext to create the
+ * context.
+ *
+ */
+static void *
+driCreateNewContext(Display *dpy, const __GLcontextModes *modes,
+ int render_type, void *sharedPrivate, __DRIcontext *pctx)
+{
+ __DRIscreen *pDRIScreen;
+ __DRIcontextPrivate *pcp;
+ __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
+ __DRIscreenPrivate *psp;
+ void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL;
+
+ pDRIScreen = __glXFindDRIScreen(dpy, modes->screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ /* ERROR!!! */
+ return NULL;
+ }
+
+ psp = (__DRIscreenPrivate *)pDRIScreen->private;
+
+ pcp = (__DRIcontextPrivate *)Xmalloc(sizeof(__DRIcontextPrivate));
+ if (!pcp) {
+ return NULL;
+ }
+
+ if (! (*create_context_with_config)(dpy, modes->screen, modes->fbconfigID,
+ &pcp->contextID, &pcp->hHWContext)) {
+ Xfree(pcp);
+ return NULL;
+ }
+
+ pcp->display = dpy;
+ pcp->driScreenPriv = psp;
+ pcp->driDrawablePriv = NULL;
+
+ /* When the first context is created for a screen, initialize a "dummy"
+ * context.
+ */
+
+ if (!psp->dummyContextPriv.driScreenPriv) {
+ psp->dummyContextPriv.contextID = 0;
+ psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
+ psp->dummyContextPriv.driScreenPriv = psp;
+ psp->dummyContextPriv.driDrawablePriv = NULL;
+ psp->dummyContextPriv.driverPrivate = NULL;
+ /* No other fields should be used! */
+ }
+
+ pctx->destroyContext = driDestroyContext;
+#ifdef DRI_NEW_INTERFACE_ONLY
+ pctx->bindContext = NULL;
+ pctx->unbindContext = NULL;
+ pctx->bindContext2 = NULL;
+ pctx->unbindContext2 = NULL;
+ pctx->bindContex3 = driBindContext3;
+ pctx->unbindContext3 = driUnbindContext3;
+#else
+ pctx->bindContext = driBindContext;
+ pctx->unbindContext = driUnbindContext;
+ if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) {
+ pctx->bindContext2 = driBindContext2;
+ pctx->unbindContext2 = driUnbindContext2;
+ }
+
+ if ( driCompareGLXAPIVersion( 20040415 ) >= 0 ) {
+ pctx->bindContext3 = driBindContext3;
+ pctx->unbindContext3 = driUnbindContext3;
+ }
+#endif
+
+ if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) {
+ (void)XF86DRIDestroyContext(dpy, modes->screen, pcp->contextID);
+ Xfree(pcp);
+ return NULL;
+ }
+
+ __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
+
+ return pcp;
+}
+
+
+#ifndef DRI_NEW_INTERFACE_ONLY
+/**
+ * Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param vis the visual information.
+ * \param sharedPrivate the shared context dependent methods or \c NULL if
+ * non-existent.
+ * \param pctx will receive the context dependent methods.
+ *
+ * \returns a opaque pointer to the per-context private information on success, or \c NULL
+ * on failure.
+ *
+ * \deprecated
+ * This function has been replaced by \c driCreateNewContext. In drivers
+ * built to work with XFree86, this function will continue to exist to support
+ * older versions of libGL. Starting with the next major relelase of XFree86,
+ * this function will be removed.
+ *
+ * \internal
+ * This function allocates and fills a __DRIcontextPrivateRec structure. It
+ * gets the visual, converts it into a __GLcontextModesRec and passes it
+ * to __DriverAPIRec::CreateContext to create the context.
+ */
+static void *driCreateContext(Display *dpy, XVisualInfo *vis,
+ void *sharedPrivate, __DRIcontext *pctx)
+{
+ __DRIscreen *pDRIScreen;
+ const __GLcontextModes *modes;
+
+ pDRIScreen = __glXFindDRIScreen(dpy, vis->screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ /* ERROR!!! */
+ return NULL;
+ }
+
+
+ /* Setup a __GLcontextModes struct corresponding to vis->visualid
+ * and create the rendering context.
+ */
+
+ modes = findConfigMode(dpy, vis->screen, vis->visualid, pDRIScreen);
+ return (modes == NULL)
+ ? NULL
+ : driCreateNewContext( dpy, modes, GLX_RGBA_TYPE,
+ sharedPrivate, pctx );
+}
+#endif /* DRI_NEW_INTERFACE_ONLY */
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Screen handling functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Destroy the per-screen private information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param screenPrivate opaque pointer to the per-screen private information.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
+ * drmClose(), and finally frees \p screenPrivate.
+ */
+static void driDestroyScreen(Display *dpy, int scrn, void *screenPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
+
+ if (psp) {
+ /* No interaction with the X-server is possible at this point. This
+ * routine is called after XCloseDisplay, so there is no protocol
+ * stream open to the X-server anymore.
+ */
+
+ if (psp->DriverAPI.DestroyScreen)
+ (*psp->DriverAPI.DestroyScreen)(psp);
+
+ (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ Xfree(psp->pDevPriv);
+ (void)drmClose(psp->fd);
+ if ( psp->modes != NULL ) {
+ _gl_context_modes_destroy( psp->modes );
+ }
+ Xfree(psp);
+ }
+}
+
+
+/**
+ * Utility function used to create a new driver-private screen structure.
+ *
+ * \param dpy Display pointer
+ * \param scrn Index of the screen
+ * \param psc DRI screen data (not driver private)
+ * \param modes Linked list of known display modes. This list is, at a
+ * minimum, a list of modes based on the current display mode.
+ * These roughly match the set of available X11 visuals, but it
+ * need not be limited to X11! The calling libGL should create
+ * a list that will inform the driver of the current display
+ * mode (i.e., color buffer depth, depth buffer depth, etc.).
+ * \param ddx_version Version of the 2D DDX. This may not be meaningful for
+ * all drivers.
+ * \param dri_version Version of the "server-side" DRI.
+ * \param drm_version Version of the kernel DRM.
+ * \param frame_buffer Data describing the location and layout of the
+ * framebuffer.
+ * \param pSAREA Pointer the the SAREA.
+ * \param fd Device handle for the DRM.
+ * \param internal_api_version Version of the internal interface between the
+ * driver and libGL.
+ * \param driverAPI Driver API functions used by other routines in dri_util.c.
+ */
+__DRIscreenPrivate *
+__driUtilCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc,
+ __GLcontextModes * modes,
+ const __DRIversion * ddx_version,
+ const __DRIversion * dri_version,
+ const __DRIversion * drm_version,
+ const __DRIframebuffer * frame_buffer,
+ drmAddress pSAREA,
+ int fd,
+ int internal_api_version,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+
+#ifdef DRI_NEW_INTERFACE_ONLY
+ if ( internal_api_version < 20040415 ) {
+ fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. "
+ "20040415 or later is required.\n", internal_api_version );
+ return NULL;
+ }
+#else
+ if ( internal_api_version == 20031201 ) {
+ fprintf( stderr, "libGL error: libGL version 20031201 has critical "
+ "binary compatilibity bugs.\nlibGL error: You must upgrade "
+ "to use direct-rendering!\n" );
+ return NULL;
+ }
+#endif /* DRI_NEW_INTERFACE_ONLY */
+
+
+ window_exists = (PFNGLXWINDOWEXISTSPROC)
+ glXGetProcAddress( (const GLubyte *) "__glXWindowExists" );
+
+ if ( window_exists == NULL ) {
+#ifdef DRI_NEW_INTERFACE_ONLY
+ fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. "
+ "20021128 or later is required.\n", internal_api_version );
+ return NULL;
+#else
+ window_exists = (PFNGLXWINDOWEXISTSPROC) __driWindowExists;
+#endif /* DRI_NEW_INTERFACE_ONLY */
+ }
+
+ create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC)
+ glXGetProcAddress( (const GLubyte *) "__glXCreateContextWithConfig" );
+ if ( create_context_with_config == NULL ) {
+#ifdef DRI_NEW_INTERFACE_ONLY
+ fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. "
+ "20031201 or later is required.\n", internal_api_version );
+ return NULL;
+#else
+ create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC)
+ fake_XF86DRICreateContextWithConfig;
+#endif /* DRI_NEW_INTERFACE_ONLY */
+ }
+
+ api_ver = internal_api_version;
+
+ psp = (__DRIscreenPrivate *)Xmalloc(sizeof(__DRIscreenPrivate));
+ if (!psp) {
+ return NULL;
+ }
+
+ /* Create the hash table */
+ psp->drawHash = drmHashCreate();
+ if ( psp->drawHash == NULL ) {
+ Xfree( psp );
+ return NULL;
+ }
+
+ psp->display = dpy;
+ psp->myNum = scrn;
+ psp->psc = psc;
+ psp->modes = modes;
+
+ /*
+ ** NOT_DONE: This is used by the X server to detect when the client
+ ** has died while holding the drawable lock. The client sets the
+ ** drawable lock to this value.
+ */
+ psp->drawLockID = 1;
+
+ psp->drmMajor = drm_version->major;
+ psp->drmMinor = drm_version->minor;
+ psp->drmPatch = drm_version->patch;
+ psp->ddxMajor = ddx_version->major;
+ psp->ddxMinor = ddx_version->minor;
+ psp->ddxPatch = ddx_version->patch;
+ psp->driMajor = dri_version->major;
+ psp->driMinor = dri_version->minor;
+ psp->driPatch = dri_version->patch;
+
+ /* install driver's callback functions */
+ memcpy( &psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec) );
+
+ psp->pSAREA = pSAREA;
+
+ psp->pFB = frame_buffer->base;
+ psp->fbSize = frame_buffer->size;
+ psp->fbStride = frame_buffer->stride;
+ psp->fbWidth = frame_buffer->width;
+ psp->fbHeight = frame_buffer->height;
+ psp->devPrivSize = frame_buffer->dev_priv_size;
+ psp->pDevPriv = frame_buffer->dev_priv;
+
+ psp->fd = fd;
+
+ /*
+ ** Do not init dummy context here; actual initialization will be
+ ** done when the first DRI context is created. Init screen priv ptr
+ ** to NULL to let CreateContext routine that it needs to be inited.
+ */
+ psp->dummyContextPriv.driScreenPriv = NULL;
+
+ psc->destroyScreen = driDestroyScreen;
+#ifndef DRI_NEW_INTERFACE_ONLY
+ psc->createContext = driCreateContext;
+#else
+ psc->createConteext = NULL;
+#endif
+ psc->createNewDrawable = driCreateNewDrawable;
+ psc->getDrawable = driGetDrawable;
+#ifdef DRI_NEW_INTERFACE_ONLY
+ psc->getMSC = driGetMSC;
+ psc->createNewContext = driCreateNewContext;
+#else
+ if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
+ psc->getMSC = driGetMSC;
+
+ if ( driCompareGLXAPIVersion( 20030824 ) >= 0 ) {
+ psc->createNewContext = driCreateNewContext;
+ }
+ }
+#endif
+
+ if ( (psp->DriverAPI.InitDriver != NULL)
+ && !(*psp->DriverAPI.InitDriver)(psp) ) {
+ Xfree( psp );
+ return NULL;
+ }
+
+
+ return psp;
+}
+
+
+#ifndef DRI_NEW_INTERFACE_ONLY
+/**
+ * Utility function used to create a new driver-private screen structure.
+ *
+ * \param dpy Display pointer.
+ * \param scrn Index of the screen.
+ * \param psc DRI screen data (not driver private)
+ * \param numConfigs Number of visual configs pointed to by \c configs.
+ * \param configs Array of GLXvisualConfigs exported by the 2D driver.
+ * \param driverAPI Driver API functions used by other routines in dri_util.c.
+ *
+ * \deprecated
+ * This function has been replaced by \c __driUtilCreateNewScreen. In drivers
+ * built to work with XFree86, this function will continue to exist to support
+ * older versions of libGL. Starting with the next major relelase of XFree86,
+ * this function will be removed.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+ int numConfigs, __GLXvisualConfig *configs,
+ const struct __DriverAPIRec *driverAPI)
+{
+ int directCapable;
+ __DRIscreenPrivate *psp = NULL;
+ drmHandle hSAREA;
+ drmAddress pSAREA;
+ char *BusID;
+ __GLcontextModes *modes;
+ __GLcontextModes *temp;
+ int i;
+ __DRIversion ddx_version;
+ __DRIversion dri_version;
+ __DRIversion drm_version;
+ __DRIframebuffer framebuffer;
+ int fd = -1;
+ int status;
+ const char * err_msg;
+ const char * err_extra;
+
+
+ if (!XF86DRIQueryDirectRenderingCapable(dpy, scrn, &directCapable)
+ || !directCapable) {
+ return NULL;
+ }
+
+
+ /* Create the linked list of context modes, and populate it with the
+ * GLX visual information passed in by libGL.
+ */
+
+ modes = _gl_context_modes_create( numConfigs, sizeof(__GLcontextModes) );
+ if ( modes == NULL ) {
+ return NULL;
+ }
+
+ temp = modes;
+ for ( i = 0 ; i < numConfigs ; i++ ) {
+ assert( temp != NULL );
+ _gl_copy_visual_to_context_mode( temp, & configs[i] );
+ temp->screen = scrn;
+
+ temp = temp->next;
+ }
+
+ err_msg = "XF86DRIOpenConnection";
+ err_extra = NULL;
+
+ if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
+ fd = drmOpen(NULL,BusID);
+ Xfree(BusID); /* No longer needed */
+
+ err_msg = "open DRM";
+ err_extra = strerror( -fd );
+
+ if (fd >= 0) {
+ drmMagic magic;
+
+ err_msg = "drmGetMagic";
+ err_extra = NULL;
+
+ if (!drmGetMagic(fd, &magic)) {
+ drmVersionPtr version = drmGetVersion(fd);
+ if (version) {
+ drm_version.major = version->version_major;
+ drm_version.minor = version->version_minor;
+ drm_version.patch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+ else {
+ drm_version.major = -1;
+ drm_version.minor = -1;
+ drm_version.patch = -1;
+ }
+
+ err_msg = "XF86DRIAuthConnection";
+ if (XF86DRIAuthConnection(dpy, scrn, magic)) {
+ char *driverName;
+
+ /*
+ * Get device name (like "tdfx") and the ddx version numbers.
+ * We'll check the version in each DRI driver's "createScreen"
+ * function.
+ */
+ err_msg = "XF86DRIGetClientDriverName";
+ if (XF86DRIGetClientDriverName(dpy, scrn,
+ &ddx_version.major,
+ &ddx_version.minor,
+ &ddx_version.patch,
+ &driverName)) {
+
+ /* No longer needed. */
+ Xfree( driverName );
+
+ /*
+ * Get the DRI X extension version.
+ */
+ err_msg = "XF86DRIQueryVersion";
+ if (XF86DRIQueryVersion(dpy,
+ &dri_version.major,
+ &dri_version.minor,
+ &dri_version.patch)) {
+ drmHandle hFB;
+ int junk;
+
+ /*
+ * Get device-specific info. pDevPriv will point to a struct
+ * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
+ * that has information about the screen size, depth, pitch,
+ * ancilliary buffers, DRM mmap handles, etc.
+ */
+ err_msg = "XF86DRIGetDeviceInfo";
+ if (XF86DRIGetDeviceInfo(dpy, scrn,
+ &hFB,
+ &junk,
+ &framebuffer.size,
+ &framebuffer.stride,
+ &framebuffer.dev_priv_size,
+ &framebuffer.dev_priv)) {
+ framebuffer.width = DisplayWidth(dpy, scrn);
+ framebuffer.height = DisplayHeight(dpy, scrn);
+
+ /*
+ * Map the framebuffer region.
+ */
+ status = drmMap(fd, hFB, framebuffer.size,
+ (drmAddressPtr)&framebuffer.base);
+
+ err_msg = "drmMap of framebuffer";
+ err_extra = strerror( -status );
+
+ if ( status == 0 ) {
+ /*
+ * Map the SAREA region. Further mmap regions may be setup in
+ * each DRI driver's "createScreen" function.
+ */
+ status = drmMap(fd, hSAREA, SAREA_MAX,
+ &pSAREA);
+
+ err_msg = "drmMap of sarea";
+ err_extra = strerror( -status );
+
+ if ( status == 0 ) {
+ PFNGLXGETINTERNALVERSIONPROC get_ver;
+
+ get_ver = (PFNGLXGETINTERNALVERSIONPROC)
+ glXGetProcAddress( (const GLubyte *) "__glXGetInternalVersion" );
+
+ err_msg = "InitDriver";
+ err_extra = NULL;
+ psp = __driUtilCreateNewScreen( dpy, scrn, psc, modes,
+ & ddx_version,
+ & dri_version,
+ & drm_version,
+ & framebuffer,
+ pSAREA,
+ fd,
+ (get_ver != NULL) ? (*get_ver)() : 1,
+ driverAPI );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( psp == NULL ) {
+ if ( pSAREA != MAP_FAILED ) {
+ (void)drmUnmap(pSAREA, SAREA_MAX);
+ }
+
+ if ( framebuffer.base != MAP_FAILED ) {
+ (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
+ }
+
+ if ( framebuffer.dev_priv != NULL ) {
+ Xfree(framebuffer.dev_priv);
+ }
+
+ if ( fd >= 0 ) {
+ (void)drmClose(fd);
+ }
+
+ if ( modes != NULL ) {
+ _gl_context_modes_destroy( modes );
+ }
+
+ (void)XF86DRICloseConnection(dpy, scrn);
+
+ if ( err_extra != NULL ) {
+ fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
+ err_extra);
+ }
+ else {
+ fprintf(stderr, "libGL error: %s failed\n", err_msg );
+ }
+
+ fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
+ }
+
+ return psp;
+}
+#endif /* DRI_NEW_INTERFACE_ONLY */
+
+
+/**
+ * Compare the current GLX API version with a driver supplied required version.
+ *
+ * The minimum required version is compared with the API version exported by
+ * the \c __glXGetInternalVersion function (in libGL.so).
+ *
+ * \param required_version Minimum required internal GLX API version.
+ * \return A tri-value return, as from strcmp is returned. A value less
+ * than, equal to, or greater than zero will be returned if the
+ * internal GLX API version is less than, equal to, or greater
+ * than \c required_version.
+ *
+ * \sa __glXGetInternalVersion().
+ */
+int driCompareGLXAPIVersion( GLuint required_version )
+{
+ if ( api_ver > required_version ) {
+ return 1;
+ }
+ else if ( api_ver == required_version ) {
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+driQueryFrameTracking( Display * dpy, void * priv,
+ int64_t * sbc, int64_t * missedFrames,
+ float * lastMissedUsage, float * usage )
+{
+ static PFNGLXGETUSTPROC get_ust;
+ __DRIswapInfo sInfo;
+ int status;
+ int64_t ust;
+ __DRIdrawablePrivate * dpriv = (__DRIdrawablePrivate *) priv;
+
+ if ( get_ust == NULL ) {
+ get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( (const GLubyte *) "__glXGetUST" );
+ }
+
+ status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
+ if ( status == 0 ) {
+ *sbc = sInfo.swap_count;
+ *missedFrames = sInfo.swap_missed_count;
+ *lastMissedUsage = sInfo.swap_missed_usage;
+
+ (*get_ust)( & ust );
+ *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
+ }
+
+ return status;
+}
+
+
+/**
+ * Calculate amount of swap interval used between GLX buffer swaps.
+ *
+ * The usage value, on the range [0,max], is the fraction of total swap
+ * interval time used between GLX buffer swaps is calculated.
+ *
+ * \f$p = t_d / (i * t_r)\f$
+ *
+ * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
+ * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
+ * required for a single vertical refresh period (as returned by \c
+ * glXGetMscRateOML).
+ *
+ * See the documentation for the GLX_MESA_swap_frame_usage extension for more
+ * details.
+ *
+ * \param dPriv Pointer to the private drawable structure.
+ * \return If less than a single swap interval time period was required
+ * between GLX buffer swaps, a number greater than 0 and less than
+ * 1.0 is returned. If exactly one swap interval time period is
+ * required, 1.0 is returned, and if more than one is required then
+ * a number greater than 1.0 will be returned.
+ *
+ * \sa glXSwapIntervalSGI glXGetMscRateOML
+ *
+ * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
+ * be possible to cache the sync rate?
+ */
+float
+driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
+ int64_t current_ust )
+{
+ static PFNGLXGETMSCRATEOMLPROC get_msc_rate = NULL;
+ int32_t n;
+ int32_t d;
+ int interval;
+ float usage = 1.0;
+
+
+ if ( get_msc_rate == NULL ) {
+ get_msc_rate = (PFNGLXGETMSCRATEOMLPROC)
+ glXGetProcAddress( (const GLubyte *) "glXGetMscRateOML" );
+ }
+
+ if ( (get_msc_rate != NULL)
+ && get_msc_rate( dPriv->display, dPriv->draw, &n, &d ) ) {
+ interval = (dPriv->pdraw->swap_interval != 0)
+ ? dPriv->pdraw->swap_interval : 1;
+
+
+ /* We want to calculate
+ * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
+ * current_UST by calling __glXGetUST. last_swap_UST is stored in
+ * dPriv->swap_ust. interval has already been calculated.
+ *
+ * The only tricky part is us_per_refresh. us_per_refresh is
+ * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
+ * around and say us_per_refresh = 1000000 * d / n. Since this goes in
+ * the denominator of the final calculation, we calculate
+ * (interval * 1000000 * d) and move n into the numerator.
+ */
+
+ usage = (current_ust - last_swap_ust);
+ usage *= n;
+ usage /= (interval * d);
+ usage /= 1000000.0;
+ }
+
+ return usage;
+}
+
+/*@}*/
+
+#endif /* GLX_DIRECT_RENDERING */