#ifdef GLX_DIRECT_RENDERING
#include <assert.h>
#include <stdarg.h>
#include <unistd.h>
#include <X11/Xlibint.h>
#include <Xext.h>
#include <extutil.h>
#include <stdio.h>
#include "glxclient.h"
#include "xf86dri.h"
#include "sarea.h"
#include "dri_util.h"
static int driQueryFrameTracking( Display * dpy, void * priv,
int64_t * sbc, int64_t * missedFrames, float * lastMissedUsage,
float * usage );
static void *driCreateDrawable(Display *dpy, int scrn, GLXDrawable draw,
GLboolean isPixmap,
VisualID vid, __DRIdrawable *pdraw);
static void driDestroyDrawable(Display *dpy, void *drawablePrivate);
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");
}
}
static GLboolean
findConfigMode(Display *dpy, int scrn, VisualID vid, __GLcontextModes *modes)
{
const __GLXvisualConfig *config;
const __DRIscreen *pDRIScreen;
const __DRIscreenPrivate *screenPriv;
int i;
pDRIScreen = __glXFindDRIScreen(dpy, scrn);
if (!pDRIScreen)
return GL_FALSE;
screenPriv = (const __DRIscreenPrivate *) pDRIScreen->private;
config = NULL;
for (i = 0; i < screenPriv->numConfigs; i++) {
if (screenPriv->configs[i].vid == vid) {
config = screenPriv->configs + i;
break;
}
}
if (!config)
return GL_FALSE;
memset(modes, 0, sizeof(__GLcontextModes));
modes->rgbMode = (config->rgba != 0);
modes->colorIndexMode = !(modes->rgbMode);
modes->doubleBufferMode = (config->doubleBuffer != 0);
modes->stereoMode = (config->stereo != 0);
modes->haveAccumBuffer = ((config->accumRedSize +
config->accumGreenSize +
config->accumBlueSize +
config->accumAlphaSize) > 0);
modes->haveDepthBuffer = (config->depthSize > 0);
modes->haveStencilBuffer = (config->stencilSize > 0);
modes->redBits = config->redSize;
modes->greenBits = config->greenSize;
modes->blueBits = config->blueSize;
modes->alphaBits = config->alphaSize;
modes->redMask = config->redMask;
modes->greenMask = config->greenMask;
modes->blueMask = config->blueMask;
modes->alphaMask = config->alphaMask;
modes->rgbBits = config->bufferSize;
modes->indexBits = config->bufferSize;
modes->accumRedBits = config->accumRedSize;
modes->accumGreenBits = config->accumGreenSize;
modes->accumBlueBits = config->accumBlueSize;
modes->accumAlphaBits = config->accumAlphaSize;
modes->depthBits = config->depthSize;
modes->stencilBits = config->stencilSize;
modes->numAuxBuffers = 0;
modes->level = config->level;
return GL_TRUE;
}
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) {
drmHashDelete(drawHash, pdp->draw);
}
}
static Bool __driWindowExistsFlag;
static int __driWindowExistsErrorHandler(Display *dpy, XErrorEvent *xerr)
{
if (xerr->error_code == BadWindow) {
__driWindowExistsFlag = GL_FALSE;
}
return 0;
}
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);
XSetErrorHandler(oldXErrorHandler);
return __driWindowExistsFlag;
}
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 (!__driWindowExists(dpy, draw)) {
__driRemoveDrawable(drawHash, pdraw);
(*pdraw->destroyDrawable)(dpy, pdraw->private);
Xfree(pdraw);
}
} while (drmHashNext(drawHash, &draw, (void **)&pdraw));
}
}
static Bool driUnbindContext2(Display *dpy, int scrn,
GLXDrawable draw, GLXDrawable read,
GLXContext gc)
{
__DRIscreen *pDRIScreen;
__DRIdrawable *pdraw;
__DRIdrawable *pread;
__DRIcontextPrivate *pcp;
__DRIscreenPrivate *psp;
__DRIdrawablePrivate *pdp;
__DRIdrawablePrivate *prp;
if (gc == NULL || draw == None || read == None) {
return GL_FALSE;
}
if (!(pDRIScreen = __glXFindDRIScreen(dpy, scrn))) {
return GL_FALSE;
} else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
return GL_FALSE;
}
pcp = (__DRIcontextPrivate *)gc->driContext.private;
pdraw = __driFindDrawable(psp->drawHash, draw);
if (!pdraw) {
return GL_FALSE;
}
pdp = (__DRIdrawablePrivate *)pdraw->private;
pread = __driFindDrawable(psp->drawHash, read);
if (!pread) {
return GL_FALSE;
}
prp = (__DRIdrawablePrivate *)pread->private;
(*psp->DriverAPI.UnbindContext)(pcp);
if (pdp->refcount == 0) {
return GL_FALSE;
}
pdp->refcount--;
if (prp != pdp) {
if (prp->refcount == 0) {
return GL_FALSE;
}
prp->refcount--;
}
#if 0
if (pdp->refcount == 0) {
__driRemoveDrawable(psp->drawHash, pdraw);
(*pdraw->destroyDrawable)(dpy, pdraw->private);
Xfree(pdraw);
}
#endif
#if 0
pcp->driDrawablePriv = NULL;
pdp->driContextPriv = &psp->dummyContextPriv;
#endif
return GL_TRUE;
}
static Bool driBindContext2(Display *dpy, int scrn,
GLXDrawable draw, GLXDrawable read,
GLXContext gc)
{
__DRIscreen *pDRIScreen;
__DRIdrawable *pdraw;
__DRIdrawablePrivate *pdp;
__DRIdrawable *pread;
__DRIdrawablePrivate *prp;
__DRIscreenPrivate *psp;
__DRIcontextPrivate *pcp;
if (gc == NULL || draw == None || read == None) {
return GL_FALSE;
}
if (!(pDRIScreen = __glXFindDRIScreen(dpy, scrn))) {
return GL_FALSE;
} else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
return GL_FALSE;
}
pdraw = __driFindDrawable(psp->drawHash, draw);
if (!pdraw) {
pdraw = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
if (!pdraw) {
return GL_FALSE;
}
pdraw->private = driCreateDrawable(dpy, scrn, draw, GL_FALSE,
gc->vid, pdraw);
if (!pdraw->private) {
Xfree(pdraw);
return GL_FALSE;
}
if (!__driAddDrawable(psp->drawHash, pdraw)) {
(*pdraw->destroyDrawable)(dpy, pdraw->private);
Xfree(pdraw);
return GL_FALSE;
}
}
pdp = (__DRIdrawablePrivate *) pdraw->private;
if (read == draw) {
prp = pdp;
}
else {
pread = __driFindDrawable(psp->drawHash, read);
if (!pread) {
pread = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
if (!pread) {
return GL_FALSE;
}
pread->private = driCreateDrawable(dpy, scrn, read, GL_FALSE,
gc->vid, pread);
if (!pread->private) {
Xfree(pread);
return GL_FALSE;
}
if (!__driAddDrawable(psp->drawHash, pread)) {
(*pread->destroyDrawable)(dpy, pread->private);
Xfree(pread);
return GL_FALSE;
}
}
prp = (__DRIdrawablePrivate *) pread->private;
}
pcp = (__DRIcontextPrivate *)gc->driContext.private;
pcp->driDrawablePriv = pdp;
pdp->driContextPriv = pcp;
pdp->refcount++;
if ( pdp != prp ) {
prp->refcount++;
}
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);
}
(*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
return GL_TRUE;
}
static Bool driBindContext(Display *dpy, int scrn,
GLXDrawable draw, GLXContext gc)
{
return driBindContext2(dpy, scrn, draw, draw, gc);
}
static Bool driUnbindContext(Display *dpy, int scrn,
GLXDrawable draw, GLXContext gc,
int will_rebind)
{
(void) will_rebind;
return driUnbindContext2( dpy, scrn, draw, draw, gc );
}
void
__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
{
__DRIscreenPrivate *psp;
__DRIcontextPrivate *pcp = pdp->driContextPriv;
if (!pcp || (pdp != pcp->driDrawablePriv)) {
return;
}
psp = pdp->driScreenPriv;
if (!psp) {
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) ||
!XF86DRIGetDrawableInfo(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
)) {
pdp->pStamp = &pdp->lastStamp;
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);
}
static void driSwapBuffers( Display *dpy, void *drawablePrivate )
{
__DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
dPriv->swapBuffers(dPriv);
(void) dpy;
}
static int driGetMSC( void *screenPrivate, int64_t *msc )
{
__DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate;
return sPriv->DriverAPI.GetMSC( sPriv, msc );
}
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 );
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 );
}
static void *driCreateDrawable_dummy(Display *dpy, int scrn,
GLXDrawable draw,
VisualID vid, __DRIdrawable *pdraw)
{
return driCreateDrawable(dpy, scrn, draw, GL_FALSE, vid, pdraw);
}
static void *driCreateDrawable(Display *dpy, int scrn, GLXDrawable draw,
GLboolean isPixmap,
VisualID vid, __DRIdrawable *pdraw)
{
__DRIscreen *pDRIScreen;
__DRIscreenPrivate *psp;
__DRIdrawablePrivate *pdp;
__GLcontextModes modes;
pdp = (__DRIdrawablePrivate *)Xmalloc(sizeof(__DRIdrawablePrivate));
if (!pdp) {
return NULL;
}
if (!XF86DRICreateDrawable(dpy, scrn, 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 = scrn;
if (!(pDRIScreen = __glXFindDRIScreen(dpy, scrn))) {
(void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw);
Xfree(pdp);
return NULL;
} else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
(void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw);
Xfree(pdp);
return NULL;
}
pdp->driScreenPriv = psp;
pdp->driContextPriv = &psp->dummyContextPriv;
if (!findConfigMode(dpy, scrn, vid, &modes))
return NULL;
if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &modes, isPixmap)) {
(void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw);
Xfree(pdp);
return NULL;
}
pdraw->destroyDrawable = driDestroyDrawable;
pdraw->swapBuffers = driSwapBuffers;
if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
pdraw->getSBC = driGetSBC;
pdraw->waitForSBC = driWaitForSBC;
pdraw->waitForMSC = driWaitForMSC;
pdraw->swapBuffersMSC = driSwapBuffersMSC;
pdraw->frameTracking = NULL;
pdraw->queryFrameTracking = driQueryFrameTracking;
pdraw->swap_interval = (getenv( "LIBGL_THROTTLE_REFRESH" ) == NULL)
? 0 : 1;
}
pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
return (void *) pdp;
}
static __DRIdrawable *driGetDrawable(Display *dpy, GLXDrawable draw,
void *screenPrivate)
{
__DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
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 (__driWindowExists(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);
}
}
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);
}
}
static void *driCreateContext(Display *dpy, XVisualInfo *vis,
void *sharedPrivate, __DRIcontext *pctx)
{
__DRIscreen *pDRIScreen;
__DRIcontextPrivate *pcp;
__DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
__DRIscreenPrivate *psp;
__GLcontextModes modes;
void *shareCtx;
if (!(pDRIScreen = __glXFindDRIScreen(dpy, vis->screen))) {
return NULL;
} else if (!(psp = (__DRIscreenPrivate *)pDRIScreen->private)) {
return NULL;
}
if (!psp->dummyContextPriv.driScreenPriv) {
if (!XF86DRICreateContext(dpy, vis->screen, vis->visual,
&psp->dummyContextPriv.contextID,
&psp->dummyContextPriv.hHWContext)) {
return NULL;
}
psp->dummyContextPriv.driScreenPriv = psp;
psp->dummyContextPriv.driDrawablePriv = NULL;
psp->dummyContextPriv.driverPrivate = NULL;
}
if (!psp->drawHash) psp->drawHash = drmHashCreate();
pcp = (__DRIcontextPrivate *)Xmalloc(sizeof(__DRIcontextPrivate));
if (!pcp) {
return NULL;
}
pcp->display = dpy;
pcp->driScreenPriv = psp;
pcp->driDrawablePriv = NULL;
if (!XF86DRICreateContext(dpy, vis->screen, vis->visual,
&pcp->contextID, &pcp->hHWContext)) {
Xfree(pcp);
return NULL;
}
if (!psp->dummyContextPriv.driScreenPriv) {
#if 0
if (!XF86DRICreateContext(dpy, vis->screen, vis->visual,
&psp->dummyContextPriv.contextID,
&psp->dummyContextPriv.hHWContext)) {
return NULL;
}
#endif
psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
psp->dummyContextPriv.driScreenPriv = psp;
psp->dummyContextPriv.driDrawablePriv = NULL;
psp->dummyContextPriv.driverPrivate = NULL;
}
if (!findConfigMode(dpy, vis->screen, vis->visualid, &modes))
return NULL;
shareCtx = pshare ? pshare->driverPrivate : NULL;
if (!(*psp->DriverAPI.CreateContext)(&modes, pcp, shareCtx)) {
(void)XF86DRIDestroyContext(dpy, vis->screen, pcp->contextID);
Xfree(pcp);
return NULL;
}
pctx->destroyContext = driDestroyContext;
pctx->bindContext = driBindContext;
pctx->unbindContext = driUnbindContext;
if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) {
pctx->bindContext2 = driBindContext2;
pctx->unbindContext2 = driUnbindContext2;
}
__driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
return pcp;
}
static void driDestroyScreen(Display *dpy, int scrn, void *screenPrivate)
{
__DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
if (psp) {
#if 0
if (psp->dummyContextPriv.driScreenPriv) {
(void)XF86DRIDestroyContext(dpy, scrn,
psp->dummyContextPriv.contextID);
}
#endif
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);
Xfree(psp);
#if 0
(void)XF86DRICloseConnection(dpy, scrn);
#endif
}
}
__DRIscreenPrivate *
__driUtilCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
int numConfigs, __GLXvisualConfig *configs,
const struct __DriverAPIRec *driverAPI)
{
int directCapable;
__DRIscreenPrivate *psp;
drmHandle hFB, hSAREA;
char *BusID, *driverName;
drmMagic magic;
if (!XF86DRIQueryDirectRenderingCapable(dpy, scrn, &directCapable)) {
return NULL;
}
if (!directCapable) {
return NULL;
}
psp = (__DRIscreenPrivate *)Xmalloc(sizeof(__DRIscreenPrivate));
if (!psp) {
return NULL;
}
psp->display = dpy;
psp->myNum = scrn;
psp->psc = psc;
psp->numConfigs = numConfigs;
psp->configs = configs;
if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
Xfree(psp);
return NULL;
}
psp->drawLockID = 1;
psp->fd = drmOpen(NULL,BusID);
if (psp->fd < 0) {
fprintf(stderr, "libGL error: failed to open DRM: %s\n", strerror(-psp->fd));
fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
Xfree(BusID);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
Xfree(BusID);
if (drmGetMagic(psp->fd, &magic)) {
fprintf(stderr, "libGL error: drmGetMagic failed\n");
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
{
drmVersionPtr version = drmGetVersion(psp->fd);
if (version) {
psp->drmMajor = version->version_major;
psp->drmMinor = version->version_minor;
psp->drmPatch = version->version_patchlevel;
drmFreeVersion(version);
}
else {
psp->drmMajor = -1;
psp->drmMinor = -1;
psp->drmPatch = -1;
}
}
if (!XF86DRIAuthConnection(dpy, scrn, magic)) {
fprintf(stderr, "libGL error: XF86DRIAuthConnection failed\n");
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
if (!XF86DRIGetClientDriverName(dpy, scrn,
&psp->ddxMajor,
&psp->ddxMinor,
&psp->ddxPatch,
&driverName)) {
fprintf(stderr, "libGL error: XF86DRIGetClientDriverName failed\n");
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
if (!XF86DRIQueryVersion(dpy,
&psp->driMajor,
&psp->driMinor,
&psp->driPatch)) {
fprintf(stderr, "libGL error: XF86DRIQueryVersion failed\n");
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
memcpy(&psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec));
if (!XF86DRIGetDeviceInfo(dpy, scrn,
&hFB,
&psp->fbOrigin,
&psp->fbSize,
&psp->fbStride,
&psp->devPrivSize,
&psp->pDevPriv)) {
fprintf(stderr, "libGL error: XF86DRIGetDeviceInfo failed\n");
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
psp->fbWidth = DisplayWidth(dpy, scrn);
psp->fbHeight = DisplayHeight(dpy, scrn);
psp->fbBPP = 32;
if (drmMap(psp->fd, hFB, psp->fbSize, (drmAddressPtr)&psp->pFB)) {
fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
Xfree(psp->pDevPriv);
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
if (drmMap(psp->fd, hSAREA, SAREA_MAX, (drmAddressPtr)&psp->pSAREA)) {
fprintf(stderr, "libGL error: drmMap of sarea failed\n");
(void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
Xfree(psp->pDevPriv);
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
if (psp->DriverAPI.InitDriver) {
if (!(*psp->DriverAPI.InitDriver)(psp)) {
fprintf(stderr, "libGL error: InitDriver failed\n");
(void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
(void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
Xfree(psp->pDevPriv);
(void)drmClose(psp->fd);
Xfree(psp);
(void)XF86DRICloseConnection(dpy, scrn);
return NULL;
}
}
psp->dummyContextPriv.driScreenPriv = NULL;
psp->drawHash = NULL;
psc->destroyScreen = driDestroyScreen;
psc->createContext = driCreateContext;
psc->createDrawable = driCreateDrawable_dummy;
psc->getDrawable = driGetDrawable;
if ( driCompareGLXAPIVersion( 20030317 ) >= 0 )
psc->getMSC = driGetMSC;
return psp;
}
int driCompareGLXAPIVersion( GLuint required_version )
{
static GLuint api_ver = 0;
if ( api_ver == 0 ) {
PFNGLXGETINTERNALVERSIONPROC get_ver;
get_ver = (PFNGLXGETINTERNALVERSIONPROC)
glXGetProcAddress( (const GLubyte *) "__glXGetInternalVersion" );
api_ver = ( get_ver != NULL ) ? get_ver() : 1;
}
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;
}
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;
usage = (current_ust - last_swap_ust);
usage *= n;
usage /= (interval * d);
usage /= 1000000.0;
}
return usage;
}
#endif