From: Keith Whitwell Date: Wed, 14 Apr 2004 12:39:58 +0000 (+0000) Subject: First pass at support for building DRI drivers in mesa tree. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=680ec7f85158eae58fd5ab56da8c66a645883cb0;p=mesa.git First pass at support for building DRI drivers in mesa tree. --- diff --git a/src/mesa/drivers/dri/dri_client/Makefile b/src/mesa/drivers/dri/dri_client/Makefile new file mode 100644 index 00000000000..14ba1948b28 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/Makefile @@ -0,0 +1,60 @@ +# src/mesa/drivers/dri/gamma/Makefile + +TOP = ../../../../.. +include $(TOP)/configs/current + +# Get rid of this: +# +DEFINES += -DGLX_DIRECT_RENDERING + +C_SOURCES = \ + dri_glx.c \ + dri_util.c \ + glcontextmodes.c \ + XF86dri.c \ + xf86drm.c \ + xf86drmHash.c \ + xf86drmRandom.c \ + xf86drmSL.c \ + + + +OBJECTS = $(C_SOURCES:.c=.o) + +INCLUDES = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/main \ + -I$(TOP)/src/mesa/glapi \ + -Iimports + + +##### RULES ##### + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + + +##### TARGETS ##### + +default: depend dri.a + + +# Run 'make dep' to update the dependencies if you change +# what's included by any source file. +depend: $(C_SOURCES) $(ASM_SOURCES) + touch depend + makedepend -fdepend -Y $(INCLUDES) \ + $(C_SOURCES) $(ASM_SOURCES) >& /dev/null + + +dri.a: $(OBJECTS) + rm -f $@ + ar rcv $@ $(OBJECTS) + ranlib $@ + +# Remove .o and backup files +clean: + -rm -f *.o */*.o *~ *.so *.a + +include depend diff --git a/src/mesa/drivers/dri/dri_client/XF86dri.c b/src/mesa/drivers/dri/dri_client/XF86dri.c new file mode 100644 index 00000000000..ea14b7a0703 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/XF86dri.c @@ -0,0 +1,636 @@ +/* $XFree86: xc/lib/GL/dri/XF86dri.c,v 1.13 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin + * Jens Owen + * Rickard E. (Rik) Faith + * + */ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +#define NEED_REPLIES +#include +#include "xf86dristr.h" +#include +#include "extutil.h" + +static XExtensionInfo _xf86dri_info_data; +static XExtensionInfo *xf86dri_info = &_xf86dri_info_data; +static char *xf86dri_extension_name = XF86DRINAME; + +#define XF86DRICheckExtension(dpy,i,val) \ + XextCheckExtension (dpy, i, xf86dri_extension_name, val) + +/***************************************************************************** + * * + * private utility routines * + * * + *****************************************************************************/ + +static int close_display(Display *dpy, XExtCodes *extCodes); +static /* const */ XExtensionHooks xf86dri_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + close_display, /* close_display */ + NULL, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + NULL, /* error_string */ +}; + +static XEXT_GENERATE_FIND_DISPLAY (find_display, xf86dri_info, + xf86dri_extension_name, + &xf86dri_extension_hooks, + 0, NULL) + +static XEXT_GENERATE_CLOSE_DISPLAY (close_display, xf86dri_info) + + +/***************************************************************************** + * * + * public XFree86-DRI Extension routines * + * * + *****************************************************************************/ + +#if 0 +#include +#define TRACE(msg) fprintf(stderr,"XF86DRI%s\n", msg); +#else +#define TRACE(msg) +#endif + + +Bool XF86DRIQueryExtension (dpy, event_basep, error_basep) + Display *dpy; + int *event_basep, *error_basep; +{ + XExtDisplayInfo *info = find_display (dpy); + + TRACE("QueryExtension..."); + if (XextHasExtension(info)) { + *event_basep = info->codes->first_event; + *error_basep = info->codes->first_error; + TRACE("QueryExtension... return True"); + return True; + } else { + TRACE("QueryExtension... return False"); + return False; + } +} + +Bool XF86DRIQueryVersion(dpy, majorVersion, minorVersion, patchVersion) + Display* dpy; + int* majorVersion; + int* minorVersion; + int* patchVersion; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIQueryVersionReply rep; + xXF86DRIQueryVersionReq *req; + + TRACE("QueryVersion..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryVersion, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryVersion; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return False"); + return False; + } + *majorVersion = rep.majorVersion; + *minorVersion = rep.minorVersion; + *patchVersion = rep.patchVersion; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return True"); + return True; +} + +Bool XF86DRIQueryDirectRenderingCapable(dpy, screen, isCapable) + Display* dpy; + int screen; + Bool* isCapable; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIQueryDirectRenderingCapableReply rep; + xXF86DRIQueryDirectRenderingCapableReq *req; + + TRACE("QueryDirectRenderingCapable..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryDirectRenderingCapable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryDirectRenderingCapable; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return False"); + return False; + } + *isCapable = rep.isCapable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return True"); + return True; +} + +Bool XF86DRIOpenConnection(dpy, screen, hSAREA, busIdString) + Display* dpy; + int screen; + drmHandlePtr hSAREA; + char **busIdString; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIOpenConnectionReply rep; + xXF86DRIOpenConnectionReq *req; + + TRACE("OpenConnection..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIOpenConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIOpenConnection; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + + *hSAREA = rep.hSAREALow; +#ifdef LONG64 + *hSAREA |= ((drmHandle)rep.hSAREAHigh) << 32; +#endif + + if (rep.length) { + if (!(*busIdString = (char *)Xcalloc(rep.busIdStringLength + 1, 1))) { + _XEatData(dpy, ((rep.busIdStringLength+3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + _XReadPad(dpy, *busIdString, rep.busIdStringLength); + } else { + *busIdString = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return True"); + return True; +} + +Bool XF86DRIAuthConnection(dpy, screen, magic) + Display* dpy; + int screen; + drmMagic magic; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIAuthConnectionReq *req; + xXF86DRIAuthConnectionReply rep; + + TRACE("AuthConnection..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIAuthConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIAuthConnection; + req->screen = screen; + req->magic = magic; + rep.authenticated = 0; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.authenticated) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return False"); + return False; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return True"); + return True; +} + +Bool XF86DRICloseConnection(dpy, screen) + Display* dpy; + int screen; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRICloseConnectionReq *req; + + TRACE("CloseConnection..."); + + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICloseConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICloseConnection; + req->screen = screen; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CloseConnection... return True"); + return True; +} + +Bool XF86DRIGetClientDriverName(dpy, screen, ddxDriverMajorVersion, + ddxDriverMinorVersion, ddxDriverPatchVersion, clientDriverName) + Display* dpy; + int screen; + int* ddxDriverMajorVersion; + int* ddxDriverMinorVersion; + int* ddxDriverPatchVersion; + char** clientDriverName; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIGetClientDriverNameReply rep; + xXF86DRIGetClientDriverNameReq *req; + + TRACE("GetClientDriverName..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetClientDriverName, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetClientDriverName; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + + *ddxDriverMajorVersion = rep.ddxDriverMajorVersion; + *ddxDriverMinorVersion = rep.ddxDriverMinorVersion; + *ddxDriverPatchVersion = rep.ddxDriverPatchVersion; + + if (rep.length) { + if (!(*clientDriverName = (char *)Xcalloc(rep.clientDriverNameLength + 1, 1))) { + _XEatData(dpy, ((rep.clientDriverNameLength+3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + _XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength); + } else { + *clientDriverName = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return True"); + return True; +} + +Bool XF86DRICreateContextWithConfig(dpy, screen, configID, context, hHWContext) + Display* dpy; + int screen; + int configID; + XID* context; + drmContextPtr hHWContext; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRICreateContextReply rep; + xXF86DRICreateContextReq *req; + + TRACE("CreateContext..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateContext; + req->visual = configID; + req->screen = screen; + *context = XAllocID(dpy); + req->context = *context; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return False"); + return False; + } + *hHWContext = rep.hHWContext; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return True"); + return True; +} + +Bool XF86DRICreateContext(dpy, screen, visual, context, hHWContext) + Display* dpy; + int screen; + Visual* visual; + XID* context; + drmContextPtr hHWContext; +{ + return XF86DRICreateContextWithConfig( dpy, screen, visual->visualid, + context, hHWContext ); +} + +Bool XF86DRIDestroyContext(dpy, screen, context) + Display* dpy; + int screen; + XID context; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIDestroyContextReq *req; + + TRACE("DestroyContext..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyContext; + req->screen = screen; + req->context = context; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyContext... return True"); + return True; +} + +Bool XF86DRICreateDrawable(dpy, screen, drawable, hHWDrawable) + Display* dpy; + int screen; + Drawable drawable; + drmDrawablePtr hHWDrawable; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRICreateDrawableReply rep; + xXF86DRICreateDrawableReq *req; + + TRACE("CreateDrawable..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateDrawable; + req->screen = screen; + req->drawable = drawable; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return False"); + return False; + } + *hHWDrawable = rep.hHWDrawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return True"); + return True; +} + +Bool XF86DRIDestroyDrawable(dpy, screen, drawable) + Display* dpy; + int screen; + Drawable drawable; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIDestroyDrawableReq *req; + + TRACE("DestroyDrawable..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyDrawable; + req->screen = screen; + req->drawable = drawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyDrawable... return True"); + return True; +} + +Bool XF86DRIGetDrawableInfo(dpy, screen, drawable, + index, stamp, X, Y, W, H, + numClipRects, pClipRects, + backX, backY, + numBackClipRects, pBackClipRects + ) + Display* dpy; + int screen; + Drawable drawable; + unsigned int* index; + unsigned int* stamp; + int* X; + int* Y; + int* W; + int* H; + int* numClipRects; + XF86DRIClipRectPtr* pClipRects; + int* backX; + int* backY; + int* numBackClipRects; + XF86DRIClipRectPtr* pBackClipRects; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIGetDrawableInfoReply rep; + xXF86DRIGetDrawableInfoReq *req; + int total_rects; + + TRACE("GetDrawableInfo..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDrawableInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDrawableInfo; + req->screen = screen; + req->drawable = drawable; + + if (!_XReply(dpy, (xReply *)&rep, 1, xFalse)) + { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } + *index = rep.drawableTableIndex; + *stamp = rep.drawableTableStamp; + *X = (int)rep.drawableX; + *Y = (int)rep.drawableY; + *W = (int)rep.drawableWidth; + *H = (int)rep.drawableHeight; + *numClipRects = rep.numClipRects; + total_rects = *numClipRects; + + *backX = rep.backX; + *backY = rep.backY; + *numBackClipRects = rep.numBackClipRects; + total_rects += *numBackClipRects; + +#if 0 + /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks + * backwards compatibility (Because of the >> 2 shift) but the fix + * enables multi-threaded apps to work. + */ + if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply) + + total_rects * sizeof(XF86DRIClipRectRec)) + 3) & ~3) >> 2)) { + _XEatData(dpy, rep.length); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } +#endif + + if (*numClipRects) { + int len = sizeof(XF86DRIClipRectRec) * (*numClipRects); + + *pClipRects = (XF86DRIClipRectPtr)Xcalloc(len, 1); + if (*pClipRects) + _XRead(dpy, (char*)*pClipRects, len); + } else { + *pClipRects = NULL; + } + + if (*numBackClipRects) { + int len = sizeof(XF86DRIClipRectRec) * (*numBackClipRects); + + *pBackClipRects = (XF86DRIClipRectPtr)Xcalloc(len, 1); + if (*pBackClipRects) + _XRead(dpy, (char*)*pBackClipRects, len); + } else { + *pBackClipRects = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return True"); + return True; +} + +Bool XF86DRIGetDeviceInfo(dpy, screen, hFrameBuffer, + fbOrigin, fbSize, fbStride, devPrivateSize, pDevPrivate) + Display* dpy; + int screen; + drmHandlePtr hFrameBuffer; + int* fbOrigin; + int* fbSize; + int* fbStride; + int* devPrivateSize; + void** pDevPrivate; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIGetDeviceInfoReply rep; + xXF86DRIGetDeviceInfoReq *req; + + TRACE("GetDeviceInfo..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDeviceInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDeviceInfo; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + + *hFrameBuffer = rep.hFrameBufferLow; +#ifdef LONG64 + *hFrameBuffer |= ((drmHandle)rep.hFrameBufferHigh) << 32; +#endif + + *fbOrigin = rep.framebufferOrigin; + *fbSize = rep.framebufferSize; + *fbStride = rep.framebufferStride; + *devPrivateSize = rep.devPrivateSize; + + if (rep.length) { + if (!(*pDevPrivate = (void *)Xcalloc(rep.devPrivateSize, 1))) { + _XEatData(dpy, ((rep.devPrivateSize+3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + _XRead(dpy, (char*)*pDevPrivate, rep.devPrivateSize); + } else { + *pDevPrivate = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return True"); + return True; +} + +#if 0 +Bool XF86DRIOpenFullScreen(dpy, screen, drawable) + Display* dpy; + int screen; + Drawable drawable; +{ + /* This function and the underlying X protocol are deprecated. + */ + (void) dpy; + (void) screen; + (void) drawable; + return False; +} + +Bool XF86DRICloseFullScreen(dpy, screen, drawable) + Display* dpy; + int screen; + Drawable drawable; +{ + /* This function and the underlying X protocol are deprecated. + */ + (void) dpy; + (void) screen; + (void) drawable; + return True; +} +#endif diff --git a/src/mesa/drivers/dri/dri_client/dri_glx.c b/src/mesa/drivers/dri/dri_client/dri_glx.c new file mode 100644 index 00000000000..f0b5f19eedd --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/dri_glx.c @@ -0,0 +1,475 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/lib/GL/dri/dri_glx.c,v 1.14 2003/07/16 00:54:00 dawes Exp $ */ + +/* + * Authors: + * Kevin E. Martin + * Brian Paul + * + */ + +#ifdef GLX_DIRECT_RENDERING + +#include +#include +#include +#include "extutil.h" +#include "glxclient.h" +#include "xf86dri.h" +#include "sarea.h" +#include +#include +#include "dri_glx.h" +#include +#include + +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + +#ifdef BUILT_IN_DRI_DRIVER + +extern void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config); + + +#else /* BUILT_IN_DRI_DRIVER */ + + +#ifndef DEFAULT_DRIVER_DIR +/* this is normally defined in the Imakefile */ +#define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri" +#endif + +static __DRIdriver *Drivers = NULL; + + +/* + * printf wrappers + */ + +static void InfoMessageF(const char *f, ...) +{ + va_list args; + const char *env; + + if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) { + fprintf(stderr, "libGL: "); + va_start(args, f); + vfprintf(stderr, f, args); + va_end(args); + } +} + +static void ErrorMessageF(const char *f, ...) +{ + va_list args; + + if (getenv("LIBGL_DEBUG")) { + fprintf(stderr, "libGL error: "); + va_start(args, f); + vfprintf(stderr, f, args); + va_end(args); + } +} + + +/* + * We'll save a pointer to this function when we couldn't find a + * direct rendering driver for a given screen. + */ +static void *DummyCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config) +{ + (void) dpy; + (void) scrn; + (void) psc; + (void) numConfigs; + (void) config; + return NULL; +} + + + +/* + * Extract the ith directory path out of a colon-separated list of + * paths. + * Input: + * index - index of path to extract (starting at zero) + * paths - the colon-separated list of paths + * dirLen - max length of result to store in + * Output: + * dir - the extracted directory path, dir[0] will be zero when + * extraction fails. + */ +static void ExtractDir(int index, const char *paths, int dirLen, char *dir) +{ + int i, len; + const char *start, *end; + + /* find ith colon */ + start = paths; + i = 0; + while (i < index) { + if (*start == ':') { + i++; + start++; + } + else if (*start == 0) { + /* end of string and couldn't find ith colon */ + dir[0] = 0; + return; + } + else { + start++; + } + } + + while (*start == ':') + start++; + + /* find next colon, or end of string */ + end = start + 1; + while (*end != ':' && *end != 0) { + end++; + } + + /* copy string between and into result string */ + len = end - start; + if (len > dirLen - 1) + len = dirLen - 1; + strncpy(dir, start, len); + dir[len] = 0; +} + + +/* + * Try to dlopen() the named driver. This function adds the + * "_dri.so" suffix to the driver name and searches the + * directories specified by the LIBGL_DRIVERS_PATH env var + * in order to find the driver. + * Input: + * driverName - a name like "tdfx", "i810", "mga", etc. + * Return: + * handle from dlopen, or NULL if driver file not found. + */ +static __DRIdriver *OpenDriver(const char *driverName) +{ + char *libPaths = NULL; + int i; + __DRIdriver *driver; + + /* First, search Drivers list to see if we've already opened this driver */ + for (driver = Drivers; driver; driver = driver->next) { + if (strcmp(driver->name, driverName) == 0) { + /* found it */ + return driver; + } + } + + if (geteuid() == getuid()) { + /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ + libPaths = getenv("LIBGL_DRIVERS_PATH"); + if (!libPaths) + libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */ + } + if (!libPaths) + libPaths = DEFAULT_DRIVER_DIR; + + for (i = 0; ; i++) { + char libDir[1000], realDriverName[200]; + void *handle; + ExtractDir(i, libPaths, 1000, libDir); + if (!libDir[0]) + break; /* ran out of paths to search */ + snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName); + InfoMessageF("OpenDriver: trying %s\n", realDriverName); + handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); + if (handle) { + /* allocate __DRIdriver struct */ + driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver)); + if (!driver) + return NULL; /* out of memory! */ + /* init the struct */ + driver->name = __glXstrdup(driverName); + if (!driver->name) { + Xfree(driver); + return NULL; /* out of memory! */ + } + + driver->createScreenFunc = (CreateScreenFunc) + dlsym(handle, "__driCreateScreen"); + driver->createNewScreenFunc = (CreateNewScreenFunc) + dlsym(handle, "__driCreateNewScreen"); + + if ( (driver->createScreenFunc == NULL) + && (driver->createNewScreenFunc == NULL) ) { + /* If the driver doesn't have this symbol then something's + * really, really wrong. + */ + ErrorMessageF("Neither __driCreateScreen or __driCreateNewScreen " + "are defined in %s_dri.so!\n", driverName); + Xfree(driver); + dlclose(handle); + continue; + } + driver->handle = handle; + /* put at head of linked list */ + driver->next = Drivers; + Drivers = driver; + return driver; + } + else { + ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror()); + } + } + + ErrorMessageF("unable to find driver: %s_dri.so\n", driverName); + return NULL; +} + + +/* + * Given a display pointer and screen number, determine the name of + * the DRI driver for the screen. (I.e. "r128", "tdfx", etc). + * Return True for success, False for failure. + */ +static Bool GetDriverName(Display *dpy, int scrNum, char **driverName) +{ + int directCapable; + Bool b; + int driverMajor, driverMinor, driverPatch; + + *driverName = NULL; + + if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) { + ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n"); + return False; + } + if (!directCapable) { + ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n"); + return False; + } + + b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor, + &driverPatch, driverName); + if (!b) { + ErrorMessageF("Cannot determine driver name for screen %d\n", scrNum); + return False; + } + + InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n", + driverMajor, driverMinor, driverPatch, *driverName, scrNum); + + return True; +} + + +/* + * Given a display pointer and screen number, return a __DRIdriver handle. + * Return NULL if anything goes wrong. + */ +__DRIdriver *driGetDriver(Display *dpy, int scrNum) +{ + char *driverName; + if (GetDriverName(dpy, scrNum, &driverName)) { + __DRIdriver *ret; + ret = OpenDriver(driverName); + if (driverName) + Xfree(driverName); + return ret; + } + return NULL; +} + + +/* + * Exported function for querying the DRI driver for a given screen. + * + * The returned char pointer points to a static array that will be + * overwritten by subsequent calls. + */ +const char *glXGetScreenDriver (Display *dpy, int scrNum) { + static char ret[32]; + char *driverName; + if (GetDriverName(dpy, scrNum, &driverName)) { + int len; + if (!driverName) + return NULL; + len = strlen (driverName); + if (len >= 31) + return NULL; + memcpy (ret, driverName, len+1); + Xfree(driverName); + return ret; + } + return NULL; +} + + +/* + * Exported function for obtaining a driver's option list (UTF-8 encoded XML). + * + * The returned char pointer points directly into the driver. Therefore + * it should be treated as a constant. + * + * If the driver was not found or does not support configuration NULL is + * returned. + * + * Note: The driver remains opened after this function returns. + */ +const char *glXGetDriverConfig (const char *driverName) { + __DRIdriver *driver = OpenDriver (driverName); + if (driver) + return dlsym (driver->handle, "__driConfigOptions"); + else + return NULL; +} + + +#endif /* BUILT_IN_DRI_DRIVER */ + + +/* This function isn't currently used. + */ +static void driDestroyDisplay(Display *dpy, void *private) +{ + __DRIdisplayPrivate *pdpyp = (__DRIdisplayPrivate *)private; + + if (pdpyp) { + const int numScreens = ScreenCount(dpy); + int i; + for (i = 0; i < numScreens; i++) { + if (pdpyp->libraryHandles[i]) + dlclose(pdpyp->libraryHandles[i]); + } + Xfree(pdpyp->libraryHandles); + Xfree(pdpyp); + } +} + + +/* + * Allocate, initialize and return a __DRIdisplayPrivate object. + * This is called from __glXInitialize() when we are given a new + * display pointer. + */ +void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp) +{ + const int numScreens = ScreenCount(dpy); + __DRIdisplayPrivate *pdpyp; + int eventBase, errorBase; + int major, minor, patch; + int scrn; + + /* Initialize these fields to NULL in case we fail. + * If we don't do this we may later get segfaults trying to free random + * addresses when the display is closed. + */ + pdisp->private = NULL; + pdisp->destroyDisplay = NULL; + pdisp->createScreen = NULL; + + if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) { + return NULL; + } + + if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) { + return NULL; + } + + pdpyp = (__DRIdisplayPrivate *)Xmalloc(sizeof(__DRIdisplayPrivate)); + if (!pdpyp) { + return NULL; + } + + pdpyp->driMajor = major; + pdpyp->driMinor = minor; + pdpyp->driPatch = patch; + + pdisp->destroyDisplay = driDestroyDisplay; + + /* allocate array of pointers to createScreen funcs */ + pdisp->createScreen = (CreateScreenFunc *) Xmalloc(numScreens * sizeof(void *)); + if (!pdisp->createScreen) { + Xfree(pdpyp); + return NULL; + } + + /* allocate array of pointers to createScreen funcs */ + pdisp->createNewScreen = (CreateNewScreenFunc *) Xmalloc(numScreens * sizeof(void *)); + if (!pdisp->createNewScreen) { + Xfree(pdisp->createScreen); + Xfree(pdpyp); + return NULL; + } + + /* allocate array of library handles */ + pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*)); + if (!pdpyp->libraryHandles) { + Xfree(pdisp->createNewScreen); + Xfree(pdisp->createScreen); + Xfree(pdpyp); + return NULL; + } + +#ifdef BUILT_IN_DRI_DRIVER + /* we'll statically bind to the built-in __driCreateScreen function */ + for (scrn = 0; scrn < numScreens; scrn++) { + pdisp->createScreen[scrn] = __driCreateScreen; + pdisp->createNewScreen[scrn] = NULL; + pdpyp->libraryHandles[scrn] = NULL; + } + +#else + /* dynamically discover DRI drivers for all screens, saving each + * driver's "__driCreateScreen" function pointer. That's the bootstrap + * entrypoint for all DRI drivers. + */ + for (scrn = 0; scrn < numScreens; scrn++) { + __DRIdriver *driver = driGetDriver(dpy, scrn); + if (driver) { + pdisp->createScreen[scrn] = driver->createScreenFunc; + pdisp->createNewScreen[scrn] = driver->createNewScreenFunc; + pdpyp->libraryHandles[scrn] = driver->handle; + } + else { + pdisp->createScreen[scrn] = DummyCreateScreen; + pdisp->createNewScreen[scrn] = NULL; + pdpyp->libraryHandles[scrn] = NULL; + } + } +#endif + + return (void *)pdpyp; +} + +#endif /* GLX_DIRECT_RENDERING */ diff --git a/src/mesa/drivers/dri/dri_client/dri_glx.h b/src/mesa/drivers/dri/dri_client/dri_glx.h new file mode 100644 index 00000000000..75561685c81 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/dri_glx.h @@ -0,0 +1,61 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin + * Brian Paul + * + */ + +#ifndef _DRI_GLX_H_ +#define _DRI_GLX_H_ + +#ifdef GLX_DIRECT_RENDERING + +struct __DRIdisplayPrivateRec { + /* + ** XFree86-DRI version information + */ + int driMajor; + int driMinor; + int driPatch; + + /* + ** Array of library handles [indexed by screen number] + */ + void **libraryHandles; +}; + +typedef struct __DRIdisplayPrivateRec __DRIdisplayPrivate; +typedef struct __DRIscreenPrivateRec __DRIscreenPrivate; +typedef struct __DRIvisualPrivateRec __DRIvisualPrivate; +typedef struct __DRIcontextPrivateRec __DRIcontextPrivate; +typedef struct __DRIdrawablePrivateRec __DRIdrawablePrivate; + +#endif +#endif /* _DRI_GLX_H_ */ diff --git a/src/mesa/drivers/dri/dri_client/dri_util.c b/src/mesa/drivers/dri/dri_client/dri_util.c new file mode 100644 index 00000000000..428472873e4 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/dri_util.c @@ -0,0 +1,1578 @@ +/* $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "xf86dri.h" +#include "sarea.h" +#include "dri_util.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 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; + + /* + ** Assume error checking is done properly in glXMakeCurrent before + ** calling driUnbindContext2. + */ + + if (gc == 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 *)gc->driContext.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 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; + 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); +#ifdef DRI_NEW_INTERFACE_ONLY + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + /* ERROR!!! */ + return GL_FALSE; + } +#else + if ( driCompareGLXAPIVersion( 20031201 ) >= 0 ) { +#endif /* DRI_NEW_INTERFACE_ONLY */ + modes = gc->mode; +#ifndef DRI_NEW_INTERFACE_ONLY + } + else { + modes = 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) ); +#endif /* DRI_NEW_INTERFACE_ONLY */ + + + /* Find the _DRIdrawable which corresponds to the writing GLXDrawable */ + psp = (__DRIscreenPrivate *)pDRIScreen->private; + 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 = (__DRIcontextPrivate *)gc->driContext.private; + 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; +} + + +/* + * 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 ); +} + +/*@}*/ + + +/*****************************************************************/ +/** \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; + pctx->bindContext = driBindContext; + pctx->unbindContext = driUnbindContext; + if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) { + pctx->bindContext2 = driBindContext2; + pctx->unbindContext2 = driUnbindContext2; + } + + 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; + + + 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; + if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { + psc->getMSC = driGetMSC; + + if ( driCompareGLXAPIVersion( 20030824 ) >= 0 ) { + psc->createNewContext = driCreateNewContext; + } + } + + 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 */ diff --git a/src/mesa/drivers/dri/dri_client/dri_util.h b/src/mesa/drivers/dri/dri_client/dri_util.h new file mode 100644 index 00000000000..f189b5a9677 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/dri_util.h @@ -0,0 +1,607 @@ +/* $XFree86: xc/lib/GL/dri/dri_util.h,v 1.1 2002/02/22 21:32:52 dawes Exp $ */ +/** + * \file dri_util.h + * DRI utility functions definitions. + * + * 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. + * + * \sa dri_util.c. + * + * \author Kevin E. Martin + * \author Brian Paul + */ + +/* + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef _DRI_UTIL_H_ +#define _DRI_UTIL_H_ + +#ifdef GLX_DIRECT_RENDERING + +#define CAPI /* XXX this should be globally defined somewhere */ + +#include +#include "glxclient.h" /* for GLXDrawable */ +/* temporary */ +/* typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); */ +#include "xf86dri.h" /* for XF86DRIClipRectPtr */ +#include "sarea.h" /* for XF86DRISAREAPtr */ +#include "GL/internal/glcore.h" /* for __GLcontextModes */ + + +typedef struct __DRIdisplayPrivateRec __DRIdisplayPrivate; +typedef struct __DRIscreenPrivateRec __DRIscreenPrivate; +typedef struct __DRIcontextPrivateRec __DRIcontextPrivate; +typedef struct __DRIdrawablePrivateRec __DRIdrawablePrivate; +typedef struct __DRIswapInfoRec __DRIswapInfo; + + +/** + * Used by DRI_VALIDATE_DRAWABLE_INFO + */ +#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \ + do { \ + if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \ + __driUtilUpdateDrawableInfo(pDrawPriv); \ + } \ + } while (0) + + +/** + * Utility macro to validate the drawable information. + * + * See __DRIdrawablePrivate::pStamp and __DRIdrawablePrivate::lastStamp. + */ +#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \ +do { \ + while (*(pdp->pStamp) != pdp->lastStamp) { \ + DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, \ + pdp->driContextPriv->hHWContext); \ + \ + DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ + DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ + DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ + \ + DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, \ + pdp->driContextPriv->hHWContext); \ + } \ +} while (0) + + +/** + * Driver callback functions. + * + * Each DRI driver must have one of these structures with all the pointers set + * to appropriate functions within the driver. + * + * When glXCreateContext() is called, for example, it'll call a helper function + * dri_util.c which in turn will jump through the \a CreateContext pointer in + * this structure. + */ +struct __DriverAPIRec { + /** + * Driver initialization callback + */ + GLboolean (*InitDriver)(__DRIscreenPrivate *driScrnPriv); + + /** + * Screen destruction callback + */ + void (*DestroyScreen)(__DRIscreenPrivate *driScrnPriv); + + /** + * Context creation callback + */ + GLboolean (*CreateContext)(const __GLcontextModes *glVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate); + + /** + * Context destruction callback + */ + void (*DestroyContext)(__DRIcontextPrivate *driContextPriv); + + /** + * Buffer (drawable) creation callback + */ + GLboolean (*CreateBuffer)(__DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + const __GLcontextModes *glVis, + GLboolean pixmapBuffer); + + /** + * Buffer (drawable) destruction callback + */ + void (*DestroyBuffer)(__DRIdrawablePrivate *driDrawPriv); + + /** + * Buffer swapping callback + */ + void (*SwapBuffers)(__DRIdrawablePrivate *driDrawPriv); + + /** + * Context activation callback + */ + GLboolean (*MakeCurrent)(__DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv); + + /** + * Context unbinding callback + */ + GLboolean (*UnbindContext)(__DRIcontextPrivate *driContextPriv); + + /** + * Full screen mode opening callback. + * + * \deprecated + * Full screen functionality is no longer used by DRI. Drivers should + * simply install a function returning \c GL_TRUE for backwards + * compatability. + * + * \todo + * Nothing calls this function anymore. Since this data structure is only + * accessed with in the driver (i.e., libGL never sees it), we need to + * remove the other cases that set this field and remove the field. + */ + GLboolean (*OpenFullScreen)(__DRIcontextPrivate *driContextPriv); + + /** + * Full screen mode closing callback. + * + * \deprecated + * Full screen functionality is no longer used by DRI. Drivers should + * simply install a function returning \c GL_TRUE for backwards + * compatability. + * + * \todo + * Nothing calls this function anymore. Since this data structure is only + * accessed with in the driver (i.e., libGL never sees it), we need to + * remove the other cases that set this field and remove the field. + */ + GLboolean (*CloseFullScreen)(__DRIcontextPrivate *driContextPriv); + + /** + * Retrieves statistics about buffer swap operations. Required if + * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported. + */ + int (*GetSwapInfo)( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo ); + + + /** + * Required if GLX_SGI_video_sync or GLX_OML_sync_control is + * supported. + */ + int (*GetMSC)( __DRIscreenPrivate * priv, int64_t * count ); + + /** + * These are required if GLX_OML_sync_control is supported. + */ + /*@{*/ + int (*WaitForMSC)( __DRIdrawablePrivate *priv, int64_t target_msc, + int64_t divisor, int64_t remainder, + int64_t * msc ); + int (*WaitForSBC)( __DRIdrawablePrivate *priv, int64_t target_sbc, + int64_t * msc, int64_t * sbc ); + + int64_t (*SwapBuffersMSC)( __DRIdrawablePrivate *priv, int64_t target_msc, + int64_t divisor, int64_t remainder ); + /*@}*/ +}; + + +struct __DRIswapInfoRec { + /** + * Number of swapBuffers operations that have been *completed*. + */ + uint64_t swap_count; + + /** + * Unadjusted system time of the last buffer swap. This is the time + * when the swap completed, not the time when swapBuffers was called. + */ + int64_t swap_ust; + + /** + * Number of swap operations that occurred after the swap deadline. That + * is if a swap happens more than swap_interval frames after the previous + * swap, it has missed its deadline. If swap_interval is 0, then the + * swap deadline is 1 frame after the previous swap. + */ + uint64_t swap_missed_count; + + /** + * Amount of time used by the last swap that missed its deadline. This + * is calculated as (__glXGetUST() - swap_ust) / (swap_interval * + * time_for_single_vrefresh)). If the actual value of swap_interval is + * 0, then 1 is used instead. If swap_missed_count is non-zero, this + * should be greater-than 1.0. + */ + float swap_missed_usage; +}; + + +typedef Bool (GetDrawableInfo)( Display *dpy, int scrn, Drawable draw, + unsigned int * index, unsigned int * stamp, + int * x, int * y, int * width, int * height, + int * numClipRects, XF86DRIClipRectPtr * pClipRects, + int * backX, int * backY, + int * numBackClipRects, XF86DRIClipRectPtr * pBackClipRects ); + + +/** + * Per-drawable private DRI driver information. + */ +struct __DRIdrawablePrivateRec { + /** + * Kernel drawable handle + */ + drmDrawable hHWDrawable; + + /** + * Driver's private drawable information. + * + * This structure is opaque. + */ + void *driverPrivate; + + /** + * X's drawable ID associated with this private drawable. + */ + GLXDrawable draw; + __DRIdrawable *pdraw; + + /** + * Reference count for number of context's currently bound to this + * drawable. + * + * Once it reaches zero, the drawable can be destroyed. + * + * \note This behavior will change with GLX 1.3. + */ + int refcount; + + /** + * Index of this drawable information in the SAREA. + */ + unsigned int index; + + /** + * Pointer to the "drawable has changed ID" stamp in the SAREA. + */ + unsigned int *pStamp; + + /** + * Last value of the stamp. + * + * If this differs from the value stored at __DRIdrawablePrivate::pStamp, + * then the drawable information has been modified by the X server, and the + * drawable information (below) should be retrieved from the X server. + */ + unsigned int lastStamp; + + /** + * \name Drawable + * + * Drawable information used in software fallbacks. + */ + /*@{*/ + int x; + int y; + int w; + int h; + int numClipRects; + XF86DRIClipRectPtr pClipRects; + /*@}*/ + + /** + * \name Back and depthbuffer + * + * Information about the back and depthbuffer where different from above. + */ + /*@{*/ + int backX; + int backY; + int backClipRectType; + int numBackClipRects; + XF86DRIClipRectPtr pBackClipRects; + /*@}*/ + + /** + * Pointer to context to which this drawable is currently bound. + */ + __DRIcontextPrivate *driContextPriv; + + /** + * Pointer to screen on which this drawable was created. + */ + __DRIscreenPrivate *driScreenPriv; + + /** + * \name Display and screen information. + * + * Basically just need these for when the locking code needs to call + * __driUtilUpdateDrawableInfo() which calls XF86DRIGetDrawableInfo(). + */ + /*@{*/ + Display *display; + int screen; + /*@}*/ + + /** + * Called via glXSwapBuffers(). + */ + void (*swapBuffers)( __DRIdrawablePrivate *dPriv ); + + /** + * Get information about the location, size, and clip rects of the + * drawable within the display. + */ + GetDrawableInfo * getInfo; +}; + +/** + * Per-context private driver information. + */ +struct __DRIcontextPrivateRec { + /** + * Kernel context handle used to access the device lock. + */ + XID contextID; + + /** + * Kernel context handle used to access the device lock. + */ + drmContext hHWContext; + + /** + * Device driver's private context data. This structure is opaque. + */ + void *driverPrivate; + + /** + * This context's display pointer. + */ + Display *display; + + /** + * Pointer to drawable currently bound to this context. + */ + __DRIdrawablePrivate *driDrawablePriv; + + /** + * Pointer to screen on which this context was created. + */ + __DRIscreenPrivate *driScreenPriv; +}; + +/** + * Per-screen private driver information. + */ +struct __DRIscreenPrivateRec { + /** + * Display for this screen + */ + Display *display; + + /** + * Current screen's number + */ + int myNum; + + /** + * Callback functions into the hardware-specific DRI driver code. + */ + struct __DriverAPIRec DriverAPI; + + /** + * \name DDX version + * DDX / 2D driver version information. + * \todo Replace these fields with a \c __DRIversionRec. + */ + /*@{*/ + int ddxMajor; + int ddxMinor; + int ddxPatch; + /*@}*/ + + /** + * \name DRI version + * DRI X extension version information. + * \todo Replace these fields with a \c __DRIversionRec. + */ + /*@{*/ + int driMajor; + int driMinor; + int driPatch; + /*@}*/ + + /** + * \name DRM version + * DRM (kernel module) version information. + * \todo Replace these fields with a \c __DRIversionRec. + */ + /*@{*/ + int drmMajor; + int drmMinor; + int drmPatch; + /*@}*/ + + /** + * ID used when the client sets the drawable lock. + * + * The X server uses this value to detect if the client has died while + * holding the drawable lock. + */ + int drawLockID; + + /** + * File descriptor returned when the kernel device driver is opened. + * + * Used to: + * - authenticate client to kernel + * - map the frame buffer, SAREA, etc. + * - close the kernel device driver + */ + int fd; + + /** + * SAREA pointer + * + * Used to access: + * - the device lock + * - the device-independent per-drawable and per-context(?) information + */ + XF86DRISAREAPtr pSAREA; + + /** + * \name Direct frame buffer access information + * Used for software fallbacks. + */ + /*@{*/ + unsigned char *pFB; + int fbSize; + int fbOrigin; + int fbStride; + int fbWidth; + int fbHeight; + int fbBPP; + /*@}*/ + + /** + * \name Device-dependent private information (stored in the SAREA). + * + * This data is accessed by the client driver only. + */ + /*@{*/ + void *pDevPriv; + int devPrivSize; + /*@}*/ + + /** + * Dummy context to which drawables are bound when not bound to any + * other context. + * + * A dummy hHWContext is created for this context, and is used by the GL + * core when a hardware lock is required but the drawable is not currently + * bound (e.g., potentially during a SwapBuffers request). The dummy + * context is created when the first "real" context is created on this + * screen. + */ + __DRIcontextPrivate dummyContextPriv; + + /** + * Hash table to hold the drawable information for this screen. + */ + void *drawHash; + + /** + * Device-dependent private information (not stored in the SAREA). + * + * This pointer is never touched by the DRI layer. + */ + void *private; + + /** + * GLX visuals / FBConfigs for this screen. These are stored as a + * linked list. + * + * \note + * This field is \b only used in conjunction with the old interfaces. If + * the new interfaces are used, this field will be set to \c NULL and will + * not be dereferenced. + */ + __GLcontextModes *modes; + + /** + * Pointer back to the \c __DRIscreen that contains this structure. + */ + + __DRIscreen *psc; +}; + + + +extern void +__driUtilMessage(const char *f, ...); + + +extern void +__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp); + + +extern __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 ); + +extern __DRIscreenPrivate * +__driUtilCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config, + const struct __DriverAPIRec *driverAPI); + +/** This must be implemented in each driver + * \deprecated + */ +extern void * +__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config); + +/** This must be implemented in each driver */ +extern void * __driCreateNewScreen( Display *dpy, int scrn, __DRIscreen *psc, + const __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, + __GLcontextModes ** driver_modes ); + +/** This is optionally implemented in each driver */ +extern void +__driRegisterExtensions( void ); + +/* Test the version of the internal GLX API. Returns a value like strcmp. */ +extern int +driCompareGLXAPIVersion( GLuint required_version ); + +extern float +driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, + int64_t last_swap_ust, int64_t current_ust ); + +#endif /* GLX_DIRECT_RENDERING */ + +#endif /* _DRI_UTIL_H_ */ diff --git a/src/mesa/drivers/dri/dri_client/drm.h b/src/mesa/drivers/dri/dri_client/drm.h new file mode 100644 index 00000000000..ceba2424f75 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/drm.h @@ -0,0 +1,680 @@ +/** + * \file drm.h + * Header for the Direct Rendering Manager + * + * \author Rickard E. (Rik) Faith + * + * \par Acknowledgments: + * Dec 1999, Richard Henderson , move to generic \c cmpxchg. + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef _DRM_H_ +#define _DRM_H_ + +#if defined(__linux__) +#include +#include /* For _IO* macros */ +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_IOC_VOID _IOC_NONE +#define DRM_IOC_READ _IOC_READ +#define DRM_IOC_WRITE _IOC_WRITE +#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE +#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__FreeBSD__) && defined(IN_MODULE) +/* Prevent name collision when including sys/ioccom.h */ +#undef ioctl +#include +#define ioctl(a,b,c) xf86ioctl(a,b,c) +#else +#include +#endif /* __FreeBSD__ && xf86ioctl */ +#define DRM_IOCTL_NR(n) ((n) & 0xff) +#define DRM_IOC_VOID IOC_VOID +#define DRM_IOC_READ IOC_OUT +#define DRM_IOC_WRITE IOC_IN +#define DRM_IOC_READWRITE IOC_INOUT +#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) +#endif + +#define XFREE86_VERSION(major,minor,patch,snap) \ + ((major << 16) | (minor << 8) | patch) + +#ifndef CONFIG_XFREE86_VERSION +#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0) +#endif + +#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) +#define DRM_PROC_DEVICES "/proc/devices" +#define DRM_PROC_MISC "/proc/misc" +#define DRM_PROC_DRM "/proc/drm" +#define DRM_DEV_DRM "/dev/drm" +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 +#endif + +#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0) +#ifdef __OpenBSD__ +#define DRM_MAJOR 81 +#endif +#if defined(__linux__) || defined(__NetBSD__) +#define DRM_MAJOR 226 +#endif +#define DRM_MAX_MINOR 15 +#endif +#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ +#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ +#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ +#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */ + +#define _DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */ +#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) +#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) +#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) + + +typedef unsigned long drm_handle_t; +typedef unsigned int drm_context_t; +typedef unsigned int drm_drawable_t; +typedef unsigned int drm_magic_t; + + +/** + * Cliprect. + * + * \warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well + * + * \note KW: Actually it's illegal to change either for + * backwards-compatibility reasons. + */ +typedef struct drm_clip_rect { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +} drm_clip_rect_t; + + +/** + * Texture region, + */ +typedef struct drm_tex_region { + unsigned char next; + unsigned char prev; + unsigned char in_use; + unsigned char padding; + unsigned int age; +} drm_tex_region_t; + +/** + * Hardware lock. + * + * The lock structure is a simple cache-line aligned integer. To avoid + * processor bus contention on a multiprocessor system, there should not be any + * other data stored in the same cache line. + */ +typedef struct drm_hw_lock { + __volatile__ unsigned int lock; /**< lock variable */ + char padding[60]; /**< Pad to cache line */ +} drm_hw_lock_t; + + +/** + * DRM_IOCTL_VERSION ioctl argument type. + * + * \sa drmGetVersion(). + */ +typedef struct drm_version { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel;/**< Patch level */ + size_t name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + size_t date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + size_t desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ +} drm_version_t; + + +/** + * DRM_IOCTL_GET_UNIQUE ioctl argument type. + * + * \sa drmGetBusid() and drmSetBusId(). + */ +typedef struct drm_unique { + size_t unique_len; /**< Length of unique */ + char *unique; /**< Unique name for driver instantiation */ +} drm_unique_t; + + +typedef struct drm_list { + int count; /**< Length of user-space structures */ + drm_version_t *version; +} drm_list_t; + + +typedef struct drm_block { + int unused; +} drm_block_t; + + +/** + * DRM_IOCTL_CONTROL ioctl argument type. + * + * \sa drmCtlInstHandler() and drmCtlUninstHandler(). + */ +typedef struct drm_control { + enum { + DRM_ADD_COMMAND, + DRM_RM_COMMAND, + DRM_INST_HANDLER, + DRM_UNINST_HANDLER + } func; + int irq; +} drm_control_t; + + +/** + * Type of memory to map. + */ +typedef enum drm_map_type { + _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /**< no caching, no core dump */ + _DRM_SHM = 2, /**< shared, cached */ + _DRM_AGP = 3, /**< AGP/GART */ + _DRM_SCATTER_GATHER = 4 /**< Scatter/gather memory for PCI DMA */ +} drm_map_type_t; + + +/** + * Memory mapping flags. + */ +typedef enum drm_map_flags { + _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */ + _DRM_READ_ONLY = 0x02, + _DRM_LOCKED = 0x04, /**< shared, cached, locked */ + _DRM_KERNEL = 0x08, /**< kernel requires access */ + _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */ + _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */ + _DRM_REMOVABLE = 0x40 /**< Removable mapping */ +} drm_map_flags_t; + + +typedef struct drm_ctx_priv_map { + unsigned int ctx_id; /**< Context requesting private mapping */ + void *handle; /**< Handle of map */ +} drm_ctx_priv_map_t; + + +/** + * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls + * argument type. + * + * \sa drmAddMap(). + */ +typedef struct drm_map { + unsigned long offset; /**< Requested physical address (0 for SAREA)*/ + unsigned long size; /**< Requested physical size (bytes) */ + drm_map_type_t type; /**< Type of memory to map */ + drm_map_flags_t flags; /**< Flags */ + void *handle; /**< User-space: "Handle" to pass to mmap() */ + /**< Kernel-space: kernel-virtual address */ + int mtrr; /**< MTRR slot used */ + /* Private data */ +} drm_map_t; + + +/** + * DRM_IOCTL_GET_CLIENT ioctl argument type. + */ +typedef struct drm_client { + int idx; /**< Which client desired? */ + int auth; /**< Is client authenticated? */ + unsigned long pid; /**< Process ID */ + unsigned long uid; /**< User ID */ + unsigned long magic; /**< Magic */ + unsigned long iocs; /**< Ioctl count */ +} drm_client_t; + + +typedef enum { + _DRM_STAT_LOCK, + _DRM_STAT_OPENS, + _DRM_STAT_CLOSES, + _DRM_STAT_IOCTLS, + _DRM_STAT_LOCKS, + _DRM_STAT_UNLOCKS, + _DRM_STAT_VALUE, /**< Generic value */ + _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */ + _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */ + + _DRM_STAT_IRQ, /**< IRQ */ + _DRM_STAT_PRIMARY, /**< Primary DMA bytes */ + _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */ + _DRM_STAT_DMA, /**< DMA */ + _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */ + _DRM_STAT_MISSED /**< Missed DMA opportunity */ + + /* Add to the *END* of the list */ +} drm_stat_type_t; + + +/** + * DRM_IOCTL_GET_STATS ioctl argument type. + */ +typedef struct drm_stats { + unsigned long count; + struct { + unsigned long value; + drm_stat_type_t type; + } data[15]; +} drm_stats_t; + + +/** + * Hardware locking flags. + */ +typedef enum drm_lock_flags { + _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ +} drm_lock_flags_t; + + +/** + * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type. + * + * \sa drmGetLock() and drmUnlock(). + */ +typedef struct drm_lock { + int context; + drm_lock_flags_t flags; +} drm_lock_t; + + +/** + * DMA flags + * + * \warning + * These values \e must match xf86drm.h. + * + * \sa drm_dma. + */ +typedef enum drm_dma_flags { + /* Flags for DMA buffer dispatch */ + _DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note The buffer may not yet have + * been processed by the hardware -- + * getting a hardware lock with the + * hardware quiescent will ensure + * that the buffer has been + * processed. + */ + _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + + /* Flags for DMA buffer request */ + _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ +} drm_dma_flags_t; + + +/** + * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type. + * + * \sa drmAddBufs(). + */ +typedef struct drm_buf_desc { + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ + enum { + _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ + _DRM_SG_BUFFER = 0x04 /**< Scatter/gather memory buffer */ + } flags; + unsigned long agp_start; /**< + * Start address of where the AGP buffers are + * in the AGP aperture + */ +} drm_buf_desc_t; + + +/** + * DRM_IOCTL_INFO_BUFS ioctl argument type. + */ +typedef struct drm_buf_info { + int count; /**< Entries in list */ + drm_buf_desc_t *list; +} drm_buf_info_t; + + +/** + * DRM_IOCTL_FREE_BUFS ioctl argument type. + */ +typedef struct drm_buf_free { + int count; + int *list; +} drm_buf_free_t; + + +/** + * Buffer information + * + * \sa drm_buf_map. + */ +typedef struct drm_buf_pub { + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + void *address; /**< Address of buffer */ +} drm_buf_pub_t; + + +/** + * DRM_IOCTL_MAP_BUFS ioctl argument type. + */ +typedef struct drm_buf_map { + int count; /**< Length of the buffer list */ + void *virtual; /**< Mmap'd area in user-virtual */ + drm_buf_pub_t *list; /**< Buffer information */ +} drm_buf_map_t; + + +/** + * DRM_IOCTL_DMA ioctl argument type. + * + * Indices here refer to the offset into the buffer list in drm_buf_get. + * + * \sa drmDMA(). + */ +typedef struct drm_dma { + int context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_indices; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send */ + drm_dma_flags_t flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size for buffers */ + int *request_indices; /**< Buffer information */ + int *request_sizes; + int granted_count; /**< Number of buffers granted */ +} drm_dma_t; + + +typedef enum { + _DRM_CONTEXT_PRESERVED = 0x01, + _DRM_CONTEXT_2DONLY = 0x02 +} drm_ctx_flags_t; + + +/** + * DRM_IOCTL_ADD_CTX ioctl argument type. + * + * \sa drmCreateContext() and drmDestroyContext(). + */ +typedef struct drm_ctx { + drm_context_t handle; + drm_ctx_flags_t flags; +} drm_ctx_t; + + +/** + * DRM_IOCTL_RES_CTX ioctl argument type. + */ +typedef struct drm_ctx_res { + int count; + drm_ctx_t *contexts; +} drm_ctx_res_t; + + +/** + * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type. + */ +typedef struct drm_draw { + drm_drawable_t handle; +} drm_draw_t; + + +/** + * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. + */ +typedef struct drm_auth { + drm_magic_t magic; +} drm_auth_t; + + +/** + * DRM_IOCTL_IRQ_BUSID ioctl argument type. + * + * \sa drmGetInterruptFromBusID(). + */ +typedef struct drm_irq_busid { + int irq; /**< IRQ number */ + int busnum; /**< bus number */ + int devnum; /**< device number */ + int funcnum; /**< function number */ +} drm_irq_busid_t; + + +typedef enum { + _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ +} drm_vblank_seq_type_t; + + +#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL + + +struct drm_wait_vblank_request { + drm_vblank_seq_type_t type; + unsigned int sequence; + unsigned long signal; +}; + + +struct drm_wait_vblank_reply { + drm_vblank_seq_type_t type; + unsigned int sequence; + long tval_sec; + long tval_usec; +}; + + +/** + * DRM_IOCTL_WAIT_VBLANK ioctl argument type. + * + * \sa drmWaitVBlank(). + */ +typedef union drm_wait_vblank { + struct drm_wait_vblank_request request; + struct drm_wait_vblank_reply reply; +} drm_wait_vblank_t; + + +/** + * DRM_IOCTL_AGP_ENABLE ioctl argument type. + * + * \sa drmAgpEnable(). + */ +typedef struct drm_agp_mode { + unsigned long mode; /**< AGP mode */ +} drm_agp_mode_t; + + +/** + * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type. + * + * \sa drmAgpAlloc() and drmAgpFree(). + */ +typedef struct drm_agp_buffer { + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for binding / unbinding */ + unsigned long type; /**< Type of memory to allocate */ + unsigned long physical; /**< Physical used by i810 */ +} drm_agp_buffer_t; + + +/** + * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type. + * + * \sa drmAgpBind() and drmAgpUnbind(). + */ +typedef struct drm_agp_binding { + unsigned long handle; /**< From drm_agp_buffer */ + unsigned long offset; /**< In bytes -- will round to page boundary */ +} drm_agp_binding_t; + + +/** + * DRM_IOCTL_AGP_INFO ioctl argument type. + * + * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(), + * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(), + * drmAgpVendorId() and drmAgpDeviceId(). + */ +typedef struct drm_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +} drm_agp_info_t; + + +/** + * DRM_IOCTL_SG_ALLOC ioctl argument type. + */ +typedef struct drm_scatter_gather { + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for mapping / unmapping */ +} drm_scatter_gather_t; + +/** + * DRM_IOCTL_SET_VERSION ioctl argument type. + */ +typedef struct drm_set_version { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +} drm_set_version_t; + + +#define DRM_IOCTL_BASE 'd' +#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) +#define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) +#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type) +#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type) + +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t) +#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t) +#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t) +#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t) +#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t) +#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, drm_set_version_t) + +#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) +#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) +#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t) +#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t) +#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t) +#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t) +#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t) +#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t) +#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t) +#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t) +#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t) + +#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, drm_map_t) + +#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, drm_ctx_priv_map_t) +#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, drm_ctx_priv_map_t) + +#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t) +#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t) +#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t) +#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t) +#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t) +#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t) +#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) +#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t) +#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t) +#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t) +#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t) +#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) +#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) + +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t) +#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) + +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + +#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) + +/** + * Device specific ioctls should only be in their respective headers + * The device specific ioctl range is from 0x40 to 0x79. + * + * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and + * drmCommandReadWrite(). + */ +#define DRM_COMMAND_BASE 0x40 + +#endif diff --git a/src/mesa/drivers/dri/dri_client/glcontextmodes.c b/src/mesa/drivers/dri/dri_client/glcontextmodes.c new file mode 100644 index 00000000000..784ad30259b --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/glcontextmodes.c @@ -0,0 +1,483 @@ +/* + * (C) Copyright IBM Corporation 2003 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file glcontextmodes.c + * Utility routines for working with \c __GLcontextModes structures. At + * some point most or all of these functions will be moved to the Mesa + * code base. + * + * \author Ian Romanick + */ + +#include +#include +#include "GL/glxint.h" + +#ifdef XFree86Server +# include "GL/glx_ansic.h" +extern void * __glXMalloc( size_t size ); +extern void __glXFree( void * ptr ); +# define Xmalloc __glXMalloc +# define Xfree __glXFree +#else +# include +# define __glXMemset memset +#endif /* XFree86Server */ + +#include "glcontextmodes.h" + +#define NUM_VISUAL_TYPES 6 + +/** + * Convert an X visual type to a GLX visual type. + * + * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) + * to be converted. + * \return If \c visualType is a valid X visual type, a GLX visual type will + * be returned. Otherwise \c GLX_NONE will be returned. + */ +GLint +_gl_convert_from_x_visual_type( int visualType ) +{ + static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { + GLX_STATIC_GRAY, GLX_GRAY_SCALE, + GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, + GLX_TRUE_COLOR, GLX_DIRECT_COLOR + }; + + return ( (unsigned) visualType < NUM_VISUAL_TYPES ) + ? glx_visual_types[ visualType ] : GLX_NONE; +} + + +/** + * Convert a GLX visual type to an X visual type. + * + * \param visualType GLX visual type (i.e., \c GLX_TRUE_COLOR, + * \c GLX_STATIC_GRAY, etc.) to be converted. + * \return If \c visualType is a valid GLX visual type, an X visual type will + * be returned. Otherwise -1 will be returned. + */ +GLint +_gl_convert_to_x_visual_type( int visualType ) +{ + static const int x_visual_types[ NUM_VISUAL_TYPES ] = { + TrueColor, DirectColor, + PseudoColor, StaticColor, + GrayScale, StaticGray + }; + + return ( (unsigned) (visualType - GLX_TRUE_COLOR) <= NUM_VISUAL_TYPES ) + ? x_visual_types[ visualType - GLX_TRUE_COLOR ] : -1; +} + + +/** + * Copy a GLX visual config structure to a GL context mode structure. All + * of the fields in \c config are copied to \c mode. Additional fields in + * \c mode that can be derrived from the fields of \c config (i.e., + * \c haveDepthBuffer) are also filled in. The remaining fields in \c mode + * that cannot be derrived are set to default values. + * + * \param mode Destination GL context mode. + * \param config Source GLX visual config. + * + * \note + * The \c fbconfigID and \c visualID fields of the \c __GLcontextModes + * structure will be set to the \c vid of the \c __GLXvisualConfig structure. + */ +void +_gl_copy_visual_to_context_mode( __GLcontextModes * mode, + const __GLXvisualConfig * config ) +{ + __GLcontextModes * const next = mode->next; + + (void) __glXMemset( mode, 0, sizeof( __GLcontextModes ) ); + mode->next = next; + + mode->visualID = config->vid; + mode->visualType = _gl_convert_from_x_visual_type( config->class ); + mode->xRenderable = GL_TRUE; + mode->fbconfigID = config->vid; + mode->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT; + + mode->rgbMode = (config->rgba != 0); + mode->renderType = (mode->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; + + mode->colorIndexMode = !(mode->rgbMode); + mode->doubleBufferMode = (config->doubleBuffer != 0); + mode->stereoMode = (config->stereo != 0); + + mode->haveAccumBuffer = ((config->accumRedSize + + config->accumGreenSize + + config->accumBlueSize + + config->accumAlphaSize) > 0); + mode->haveDepthBuffer = (config->depthSize > 0); + mode->haveStencilBuffer = (config->stencilSize > 0); + + mode->redBits = config->redSize; + mode->greenBits = config->greenSize; + mode->blueBits = config->blueSize; + mode->alphaBits = config->alphaSize; + mode->redMask = config->redMask; + mode->greenMask = config->greenMask; + mode->blueMask = config->blueMask; + mode->alphaMask = config->alphaMask; + mode->rgbBits = config->bufferSize; + mode->indexBits = config->bufferSize; + + mode->accumRedBits = config->accumRedSize; + mode->accumGreenBits = config->accumGreenSize; + mode->accumBlueBits = config->accumBlueSize; + mode->accumAlphaBits = config->accumAlphaSize; + mode->depthBits = config->depthSize; + mode->stencilBits = config->stencilSize; + + mode->numAuxBuffers = config->auxBuffers; + mode->level = config->level; + + mode->visualRating = config->visualRating; + mode->transparentPixel = config->transparentPixel; + mode->transparentRed = config->transparentRed; + mode->transparentGreen = config->transparentGreen; + mode->transparentBlue = config->transparentBlue; + mode->transparentAlpha = config->transparentAlpha; + mode->transparentIndex = config->transparentIndex; + + mode->swapMethod = GLX_SWAP_UNDEFINED_OML; +} + + +/** + * Get data from a GL context mode. + * + * \param mode GL context mode whose data is to be returned. + * \param attribute Attribute of \c mode that is to be returned. + * \param value_return Location to store the data member of \c mode. + * \return If \c attribute is a valid attribute of \c mode, \c Success is + * returned. Otherwise \c GLX_BAD_ATTRIBUTE is returned. + */ +int +_gl_get_context_mode_data(const __GLcontextModes *mode, int attribute, + int *value_return) +{ + switch (attribute) { + case GLX_USE_GL: + *value_return = GL_TRUE; + return Success; + case GLX_BUFFER_SIZE: + *value_return = mode->rgbBits; + return Success; + case GLX_RGBA: + *value_return = mode->rgbMode; + return Success; + case GLX_RED_SIZE: + *value_return = mode->redBits; + return Success; + case GLX_GREEN_SIZE: + *value_return = mode->greenBits; + return Success; + case GLX_BLUE_SIZE: + *value_return = mode->blueBits; + return Success; + case GLX_ALPHA_SIZE: + *value_return = mode->alphaBits; + return Success; + case GLX_DOUBLEBUFFER: + *value_return = mode->doubleBufferMode; + return Success; + case GLX_STEREO: + *value_return = mode->stereoMode; + return Success; + case GLX_AUX_BUFFERS: + *value_return = mode->numAuxBuffers; + return Success; + case GLX_DEPTH_SIZE: + *value_return = mode->depthBits; + return Success; + case GLX_STENCIL_SIZE: + *value_return = mode->stencilBits; + return Success; + case GLX_ACCUM_RED_SIZE: + *value_return = mode->accumRedBits; + return Success; + case GLX_ACCUM_GREEN_SIZE: + *value_return = mode->accumGreenBits; + return Success; + case GLX_ACCUM_BLUE_SIZE: + *value_return = mode->accumBlueBits; + return Success; + case GLX_ACCUM_ALPHA_SIZE: + *value_return = mode->accumAlphaBits; + return Success; + case GLX_LEVEL: + *value_return = mode->level; + return Success; + case GLX_TRANSPARENT_TYPE_EXT: + *value_return = mode->transparentPixel; + return Success; + case GLX_TRANSPARENT_RED_VALUE: + *value_return = mode->transparentRed; + return Success; + case GLX_TRANSPARENT_GREEN_VALUE: + *value_return = mode->transparentGreen; + return Success; + case GLX_TRANSPARENT_BLUE_VALUE: + *value_return = mode->transparentBlue; + return Success; + case GLX_TRANSPARENT_ALPHA_VALUE: + *value_return = mode->transparentAlpha; + return Success; + case GLX_TRANSPARENT_INDEX_VALUE: + *value_return = mode->transparentIndex; + return Success; + case GLX_X_VISUAL_TYPE: + *value_return = mode->visualType; + return Success; + case GLX_CONFIG_CAVEAT: + *value_return = mode->visualRating; + return Success; + case GLX_VISUAL_ID: + *value_return = mode->visualID; + return Success; + case GLX_DRAWABLE_TYPE: + *value_return = mode->drawableType; + return Success; + case GLX_RENDER_TYPE: + *value_return = mode->renderType; + return Success; + case GLX_X_RENDERABLE: + *value_return = mode->xRenderable; + return Success; + case GLX_FBCONFIG_ID: + *value_return = mode->fbconfigID; + return Success; + case GLX_MAX_PBUFFER_WIDTH: + *value_return = mode->maxPbufferWidth; + return Success; + case GLX_MAX_PBUFFER_HEIGHT: + *value_return = mode->maxPbufferHeight; + return Success; + case GLX_MAX_PBUFFER_PIXELS: + *value_return = mode->maxPbufferPixels; + return Success; + case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: + *value_return = mode->optimalPbufferWidth; + return Success; + case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: + *value_return = mode->optimalPbufferHeight; + return Success; + case GLX_SWAP_METHOD_OML: + *value_return = mode->swapMethod; + return Success; + case GLX_SAMPLE_BUFFERS_SGIS: + *value_return = mode->sampleBuffers; + return Success; + case GLX_SAMPLES_SGIS: + *value_return = mode->samples; + return Success; + + /* Applications are NOT allowed to query GLX_VISUAL_SELECT_GROUP_SGIX. + * It is ONLY for communication between the GLX client and the GLX + * server. + */ + case GLX_VISUAL_SELECT_GROUP_SGIX: + default: + return GLX_BAD_ATTRIBUTE; + } +} + + +/** + * Allocate a linked list of \c __GLcontextModes structures. The fields of + * each structure will be initialized to "reasonable" default values. In + * most cases this is the default value defined by table 3.4 of the GLX + * 1.3 specification. This means that most values are either initialized to + * zero or \c GLX_DONT_CARE (which is -1). As support for additional + * extensions is added, the new values will be initialized to appropriate + * values from the extension specification. + * + * \param count Number of structures to allocate. + * \param minimum_size Minimum size of a structure to allocate. This allows + * for differences in the version of the + * \c __GLcontextModes stucture used in libGL and in a + * DRI-based driver. + * \returns A pointer to the first element in a linked list of \c count + * stuctures on success, or \c NULL on failure. + * + * \warning Use of \c minimum_size does \b not guarantee binary compatibility. + * The fundamental assumption is that if the \c minimum_size + * specified by the driver and the size of the \c __GLcontextModes + * structure in libGL is the same, then the meaning of each byte in + * the structure is the same in both places. \b Be \b careful! + * Basically this means that fields have to be added in libGL and + * then propagated to drivers. Drivers should \b never arbitrarilly + * extend the \c __GLcontextModes data-structure. + */ +__GLcontextModes * +_gl_context_modes_create( unsigned count, size_t minimum_size ) +{ + const size_t size = (minimum_size > sizeof( __GLcontextModes )) + ? minimum_size : sizeof( __GLcontextModes ); + __GLcontextModes * base = NULL; + __GLcontextModes ** next; + unsigned i; + + next = & base; + for ( i = 0 ; i < count ; i++ ) { + *next = (__GLcontextModes *) Xmalloc( size ); + if ( *next == NULL ) { + _gl_context_modes_destroy( base ); + base = NULL; + break; + } + + (void) __glXMemset( *next, 0, size ); + (*next)->visualID = GLX_DONT_CARE; + (*next)->visualType = GLX_DONT_CARE; + (*next)->visualRating = GLX_NONE; + (*next)->transparentPixel = GLX_NONE; + (*next)->transparentRed = GLX_DONT_CARE; + (*next)->transparentGreen = GLX_DONT_CARE; + (*next)->transparentBlue = GLX_DONT_CARE; + (*next)->transparentAlpha = GLX_DONT_CARE; + (*next)->transparentIndex = GLX_DONT_CARE; + (*next)->xRenderable = GLX_DONT_CARE; + (*next)->fbconfigID = GLX_DONT_CARE; + (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; + + next = & ((*next)->next); + } + + return base; +} + + +/** + * Destroy a linked list of \c __GLcontextModes structures created by + * \c _gl_context_modes_create. + * + * \param modes Linked list of structures to be destroyed. All structres + * in the list will be freed. + */ +void +_gl_context_modes_destroy( __GLcontextModes * modes ) +{ + while ( modes != NULL ) { + __GLcontextModes * const next = modes->next; + + Xfree( modes ); + modes = next; + } +} + + +/** + * Find a context mode matching a Visual ID. + * + * \param modes List list of context-mode structures to be searched. + * \param vid Visual ID to be found. + * \returns A pointer to a context-mode in \c modes if \c vid was found in + * the list, or \c NULL if it was not. + */ + +__GLcontextModes * +_gl_context_modes_find_visual( __GLcontextModes * modes, int vid ) +{ + while ( modes != NULL ) { + if ( modes->visualID == vid ) { + break; + } + + modes = modes->next; + } + + return modes; +} + + +/** + * Determine if two context-modes are the same. This is intended to be used + * by libGL implementations to compare to sets of driver generated FBconfigs. + * + * \param a Context-mode to be compared. + * \param b Context-mode to be compared. + * \returns \c GL_TRUE if the two context-modes are the same. \c GL_FALSE is + * returned otherwise. + */ +GLboolean +_gl_context_modes_are_same( const __GLcontextModes * a, + const __GLcontextModes * b ) +{ + return( (a->rgbMode == b->rgbMode) && + (a->floatMode == b->floatMode) && + (a->colorIndexMode == b->colorIndexMode) && + (a->doubleBufferMode == b->doubleBufferMode) && + (a->stereoMode == b->stereoMode) && + (a->redBits == b->redBits) && + (a->greenBits == b->greenBits) && + (a->blueBits == b->blueBits) && + (a->alphaBits == b->alphaBits) && +#if 0 /* For some reason these don't get set on the client-side in libGL. */ + (a->redMask == b->redMask) && + (a->greenMask == b->greenMask) && + (a->blueMask == b->blueMask) && + (a->alphaMask == b->alphaMask) && +#endif + (a->rgbBits == b->rgbBits) && + (a->indexBits == b->indexBits) && + (a->accumRedBits == b->accumRedBits) && + (a->accumGreenBits == b->accumGreenBits) && + (a->accumBlueBits == b->accumBlueBits) && + (a->accumAlphaBits == b->accumAlphaBits) && + (a->depthBits == b->depthBits) && + (a->stencilBits == b->stencilBits) && + (a->numAuxBuffers == b->numAuxBuffers) && + (a->level == b->level) && + (a->pixmapMode == b->pixmapMode) && + (a->visualRating == b->visualRating) && + + (a->transparentPixel == b->transparentPixel) && + + ((a->transparentPixel != GLX_TRANSPARENT_RGB) || + ((a->transparentRed == b->transparentRed) && + (a->transparentGreen == b->transparentGreen) && + (a->transparentBlue == b->transparentBlue) && + (a->transparentAlpha == b->transparentAlpha))) && + + ((a->transparentPixel != GLX_TRANSPARENT_INDEX) || + (a->transparentIndex == b->transparentIndex)) && + + (a->sampleBuffers == b->sampleBuffers) && + (a->samples == b->samples) && + ((a->drawableType & b->drawableType) != 0) && + (a->renderType == b->renderType) && + (a->maxPbufferWidth == b->maxPbufferWidth) && + (a->maxPbufferHeight == b->maxPbufferHeight) && + (a->maxPbufferPixels == b->maxPbufferPixels) && + (a->optimalPbufferWidth == b->optimalPbufferWidth) && + (a->optimalPbufferHeight == b->optimalPbufferHeight) && + (a->swapMethod == b->swapMethod) ); +} diff --git a/src/mesa/drivers/dri/dri_client/glcontextmodes.h b/src/mesa/drivers/dri/dri_client/glcontextmodes.h new file mode 100644 index 00000000000..5f8fa4f3116 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/glcontextmodes.h @@ -0,0 +1,49 @@ +/* + * (C) Copyright IBM Corporation 2003 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file glcontextmodes.h + * \author Ian Romanick + */ + +#ifndef GLCONTEXTMODES_H +#define GLCONTEXTMODES_H + +#include "GL/internal/glcore.h" + +extern GLint _gl_convert_from_x_visual_type( int visualType ); +extern GLint _gl_convert_to_x_visual_type( int visualType ); +extern void _gl_copy_visual_to_context_mode( __GLcontextModes * mode, + const __GLXvisualConfig * config ); +extern int _gl_get_context_mode_data( const __GLcontextModes *mode, + int attribute, int *value_return ); +extern __GLcontextModes * _gl_context_modes_create( unsigned count, + size_t minimum_size ); +extern void _gl_context_modes_destroy( __GLcontextModes * modes ); +extern __GLcontextModes * _gl_context_modes_find_visual( + __GLcontextModes * modes, int vid ); +extern GLboolean _gl_context_modes_are_same( const __GLcontextModes * a, + const __GLcontextModes * b ); + +#endif /* GLCONTEXTMODES_H */ diff --git a/src/mesa/drivers/dri/dri_client/imports/glxclient.h b/src/mesa/drivers/dri/dri_client/imports/glxclient.h new file mode 100644 index 00000000000..317ea011169 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/imports/glxclient.h @@ -0,0 +1,1143 @@ +/* +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: The application programming interfaces +** established by SGI in conjunction with the Original Code are The +** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released +** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version +** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X +** Window System(R) (Version 1.3), released October 19, 1998. This software +** was created using the OpenGL(R) version 1.2.1 Sample Implementation +** published by SGI, but has not been independently verified as being +** compliant with the OpenGL(R) version 1.2.1 Specification. +*/ +/* $XFree86: xc/lib/GL/glx/glxclient.h,v 1.15 2002/10/30 12:51:26 alanh Exp $ */ + +/** + * \file glxclient.h + * Direct rendering support added by Precision Insight, Inc. + * + * \author Kevin E. Martin + */ + +#ifndef _GLX_client_h_ +#define _GLX_client_h_ +#define NEED_REPLIES +#define NEED_EVENTS +#include +#include +#define GLX_GLXEXT_PROTOTYPES +#include +#include +#include +#include +#include "GL/glxint.h" +#include "GL/glxproto.h" +#include "GL/internal/glcore.h" +#include "glapitable.h" +#ifdef NEED_GL_FUNCS_WRAPPED +#include "indirect.h" +#endif +#ifdef XTHREADS +#include "Xthreads.h" +#endif +#ifdef GLX_BUILT_IN_XMESA +#include "realglx.h" /* just silences prototype warnings */ +#endif + +#define GLX_MAJOR_VERSION 1 /* current version numbers */ +#define GLX_MINOR_VERSION 2 + +#define __GLX_MAX_TEXTURE_UNITS 32 + +typedef struct __GLXcontextRec __GLXcontext; +typedef struct __GLXdisplayPrivateRec __GLXdisplayPrivate; +typedef struct _glapi_table __GLapi; + +/************************************************************************/ + +#ifdef GLX_DIRECT_RENDERING + +/** + * \name DRI interface structures + * + * The following structures define the interface between the GLX client + * side library and the DRI (direct rendering infrastructure). + */ +/*@{*/ +typedef struct __DRIdisplayRec __DRIdisplay; +typedef struct __DRIscreenRec __DRIscreen; +typedef struct __DRIcontextRec __DRIcontext; +typedef struct __DRIdrawableRec __DRIdrawable; +typedef struct __DRIdriverRec __DRIdriver; +typedef struct __DRIframebufferRec __DRIframebuffer; +typedef struct __DRIversionRec __DRIversion; +/*@}*/ + +extern __DRIscreen *__glXFindDRIScreen(Display *dpy, int scrn); + +/** + * Stored version of some component (i.e., server-side DRI module, kernel-side + * DRM, etc.). + * + * \todo There are several data structures that explicitly store a major + * version, minor version, and patch level. These structures should + * be modified to have a \c __DRIversionRec instead. + */ +struct __DRIversionRec { + int major; /**< Major version number. */ + int minor; /**< Minor version number. */ + int patch; /**< Patch-level. */ +}; + +/** + * Framebuffer information record. Used by libGL to communicate information + * about the framebuffer to the driver's \c __DRIdisplayRec::createNewScreen + * function. + * + * In XFree86, most of this information is derrived from data returned by + * calling \c XF86DRIGetDeviceInfo. + * + * \sa XF86DRIGetDeviceInfo __DRIdisplayRec::createNewScreen + * __driUtilCreateNewScreen CallCreateNewScreen + * + * \bug This structure could be better named. + */ +struct __DRIframebufferRec { + unsigned char *base; /**< Framebuffer base address in the CPU's + * address space. This value is calculated by + * calling \c drmMap on the framebuffer handle + * returned by \c XF86DRIGetDeviceInfo (or a + * similar function). + */ + int size; /**< Framebuffer size, in bytes. */ + int stride; /**< Number of bytes from one line to the next. */ + int width; /**< Pixel width of the framebuffer. */ + int height; /**< Pixel height of the framebuffer. */ + int dev_priv_size; /**< Size of the driver's dev-priv structure. */ + void *dev_priv; /**< Pointer to the driver's dev-priv structure. */ +}; + +typedef void *(*CreateScreenFunc)(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config); + +typedef void *(*CreateNewScreenFunc)(Display *dpy, int scrn, __DRIscreen *psc, + const __GLcontextModes * modes, const __DRIversion * ddx_version, + const __DRIversion * dri_version, const __DRIversion * drm_version, + const __DRIframebuffer * frame_buffer, void * pSAREA, + int fd, int internal_api_version, __GLcontextModes ** driver_modes); + +/** + * Display dependent methods. This structure is initialized during the + * \c driCreateDisplay call. + */ +struct __DRIdisplayRec { + /** + * Method to destroy the private DRI display data. + */ + void (*destroyDisplay)(Display *dpy, void *displayPrivate); + + /** + * Methods to create the private DRI screen data and initialize the + * screen dependent methods. + * This is an array [indexed by screen number] of function pointers. + * + * \deprecated This array of function pointers has been replaced by + * \c __DRIdisplayRec::createNewScreen. + * \sa __DRIdisplayRec::createNewScreen + */ + CreateScreenFunc * createScreen; + + /** + * Opaque pointer to private per display direct rendering data. + * \c NULL if direct rendering is not supported on this display. + */ + struct __DRIdisplayPrivateRec *private; + + /** + * Array of pointers to methods to create and initialize the private DRI + * screen data. + * + * \sa __DRIdisplayRec::createScreen + */ + CreateNewScreenFunc * createNewScreen; +}; + +/** + * Screen dependent methods. This structure is initialized during the + * \c __DRIdisplayRec::createScreen call. + */ +struct __DRIscreenRec { + /** + * Method to destroy the private DRI screen data. + */ + void (*destroyScreen)(Display *dpy, int scrn, void *screenPrivate); + + /** + * Method to create the private DRI context data and initialize the + * context dependent methods. + * + * \sa __DRIscreenRec::createNewContext driCreateContext + * driCreateNewContext + * \deprecated This function has been replaced by + * __DRIscreenRec::createNewContext. New drivers will + * continue to export this method, but it will eventually + * (in the next XFree86 major relearse) go away. + */ + void *(*createContext)(Display *dpy, XVisualInfo *vis, void *sharedPrivate, + __DRIcontext *pctx); + + /** + * Method to create the private DRI drawable data and initialize the + * drawable dependent methods. + */ + void *(*createNewDrawable)(Display *dpy, const __GLcontextModes *modes, + GLXDrawable draw, __DRIdrawable *pdraw, + int renderType, const int *attrs); + + /** + * Method to return a pointer to the DRI drawable data. + */ + __DRIdrawable *(*getDrawable)(Display *dpy, GLXDrawable draw, + void *drawablePrivate); + + /** + * Opaque pointer to private per screen direct rendering data. \c NULL + * if direct rendering is not supported on this screen. Never + * dereferenced in libGL. + */ + void *private; + + /** + * Get the number of vertical refreshes since some point in time before + * this function was first called (i.e., system start up). + * + * \since Internal API version 20030317. + */ + int (*getMSC)( void *screenPrivate, int64_t *msc ); + + /** + * Opaque pointer that points back to the containing + * \c __GLXscreenConfigs. This data structure is shared with DRI drivers + * but \c __GLXscreenConfigs is not. However, they are needed by some GLX + * functions called by DRI drivers. + * + * \since Internal API version 20030813. + */ + void *screenConfigs; + + /** + * Functions associated with MESA_allocate_memory. + * + * \since Internal API version 20030815. + */ + /*@{*/ + void *(*allocateMemory)(Display *dpy, int scrn, GLsizei size, + GLfloat readfreq, GLfloat writefreq, + GLfloat priority); + + void (*freeMemory)(Display *dpy, int scrn, GLvoid *pointer); + + GLuint (*memoryOffset)(Display *dpy, int scrn, const GLvoid *pointer); + /*@}*/ + + /** + * Method to create the private DRI context data and initialize the + * context dependent methods. + * + * \since Internal API version 20031201. + */ + void * (*createNewContext)(Display *dpy, const __GLcontextModes *modes, + int render_type, + void *sharedPrivate, __DRIcontext *pctx); +}; + +/** + * Context dependent methods. This structure is initialized during the + * \c __DRIscreenRec::createContext call. + */ +struct __DRIcontextRec { + /** + * Method to destroy the private DRI context data. + */ + void (*destroyContext)(Display *dpy, int scrn, void *contextPrivate); + + /** + * Method to bind a DRI drawable to a DRI graphics context. + */ + Bool (*bindContext)(Display *dpy, int scrn, GLXDrawable draw, + GLXContext gc); + + /** + * Method to unbind a DRI drawable to a DRI graphics context. + */ + Bool (*unbindContext)(Display *dpy, int scrn, GLXDrawable draw, + GLXContext gc, int will_rebind); + + /** + * Opaque pointer to private per context direct rendering data. + * \c NULL if direct rendering is not supported on the display or + * screen used to create this context. Never dereferenced in libGL. + */ + void *private; + + /** + * Method to bind a DRI drawable to a DRI graphics context. + * + * \since Internal API version 20030606. + */ + Bool (*bindContext2)(Display *dpy, int scrn, GLXDrawable draw, + GLXDrawable read, GLXContext gc); + + /** + * Method to unbind a DRI drawable to a DRI graphics context. + * + * \since Internal API version 20030606. + */ + Bool (*unbindContext2)(Display *dpy, int scrn, GLXDrawable draw, + GLXDrawable read, GLXContext gc); +}; + +/** + * Drawable dependent methods. This structure is initialized during the + * \c __DRIscreenRec::createDrawable call. \c createDrawable is not called + * by libGL at this time. It's currently used via the dri_util.c utility code + * instead. + */ +struct __DRIdrawableRec { + /** + * Method to destroy the private DRI drawable data. + */ + void (*destroyDrawable)(Display *dpy, void *drawablePrivate); + + /** + * Method to swap the front and back buffers. + */ + void (*swapBuffers)(Display *dpy, void *drawablePrivate); + + /** + * Opaque pointer to private per drawable direct rendering data. + * \c NULL if direct rendering is not supported on the display or + * screen used to create this drawable. Never dereferenced in libGL. + */ + void *private; + + /** + * Get the number of completed swap buffers for this drawable. + * + * \since Internal API version 20030317. + */ + int (*getSBC)(Display *dpy, void *drawablePrivate, int64_t *sbc ); + + /** + * Wait for the SBC to be greater than or equal target_sbc. + * + * \since Internal API version 20030317. + */ + int (*waitForSBC)( Display * dpy, void *drawablePriv, + int64_t target_sbc, + int64_t * msc, int64_t * sbc ); + + /** + * Wait for the MSC to equal target_msc, or, if that has already passed, + * the next time (MSC % divisor) is equal to remainder. If divisor is + * zero, the function will return as soon as MSC is greater than or equal + * to target_msc. + * + * \since Internal API version 20030317. + */ + int (*waitForMSC)( Display * dpy, void *drawablePriv, + int64_t target_msc, int64_t divisor, int64_t remainder, + int64_t * msc, int64_t * sbc ); + + /** + * Like \c swapBuffers, but does NOT have an implicit \c glFlush. Once + * rendering is complete, waits until MSC is equal to target_msc, or + * if that has already passed, waits until (MSC % divisor) is equal + * to remainder. If divisor is zero, the swap will happen as soon as + * MSC is greater than or equal to target_msc. + * + * \since Internal API version 20030317. + */ + int64_t (*swapBuffersMSC)(Display *dpy, void *drawablePrivate, + int64_t target_msc, + int64_t divisor, int64_t remainder); + + /** + * Enable or disable frame usage tracking. + * + * \since Internal API version 20030317. + */ + int (*frameTracking)(Display *dpy, void *drawablePrivate, Bool enable); + + /** + * Retrieve frame usage information. + * + * \since Internal API version 20030317. + */ + int (*queryFrameTracking)(Display *dpy, void *drawablePrivate, + int64_t * sbc, int64_t * missedFrames, + float * lastMissedUsage, float * usage ); + + /** + * Used by drivers that implement the GLX_SGI_swap_control or + * GLX_MESA_swap_control extension. + * + * \since Internal API version 20030317. + */ + unsigned swap_interval; +}; + + +/* +** We keep a linked list of these structures, one per DRI device driver. +*/ +struct __DRIdriverRec { + const char *name; + void *handle; + CreateScreenFunc createScreenFunc; + CreateNewScreenFunc createNewScreenFunc; + struct __DRIdriverRec *next; +}; + +/* +** Function to create and DRI display data and initialize the display +** dependent methods. +*/ +extern void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp); + +extern __DRIdriver *driGetDriver(Display *dpy, int scrNum); + +extern void DRI_glXUseXFont( Font font, int first, int count, int listbase ); + +/* +** Functions to obtain driver configuration information from a direct +** rendering client application +*/ +extern const char *glXGetScreenDriver (Display *dpy, int scrNum); + +extern const char *glXGetDriverConfig (const char *driverName); + +#endif + +/************************************************************************/ + +#define __GL_CLIENT_ATTRIB_STACK_DEPTH 16 + +typedef struct __GLXpixelStoreModeRec { + GLboolean swapEndian; + GLboolean lsbFirst; + GLuint rowLength; + GLuint imageHeight; + GLuint imageDepth; + GLuint skipRows; + GLuint skipPixels; + GLuint skipImages; + GLuint alignment; +} __GLXpixelStoreMode; + +/* The next 3 structures are deprecated. Client state is no longer tracked + * using them. They only remain to maintain the layout / structure offset of + * __GLXcontextRec. In XFree86 5.0 they will be removed altogether. + */ + +typedef struct __GLXvertexArrayPointerStateRecDEPRECATED { + GLboolean enable; + void (*proc)(const void *); + const GLubyte *ptr; + GLsizei skip; + GLint size; + GLenum type; + GLsizei stride; +} __GLXvertexArrayPointerStateDEPRECATED; + +typedef struct __GLXvertArrayStateRecDEPRECATED { + __GLXvertexArrayPointerStateDEPRECATED vertex; + __GLXvertexArrayPointerStateDEPRECATED normal; + __GLXvertexArrayPointerStateDEPRECATED color; + __GLXvertexArrayPointerStateDEPRECATED index; + __GLXvertexArrayPointerStateDEPRECATED texCoord[__GLX_MAX_TEXTURE_UNITS]; + __GLXvertexArrayPointerStateDEPRECATED edgeFlag; + GLint maxElementsVertices; + GLint maxElementsIndices; + GLint activeTexture; +} __GLXvertArrayStateDEPRECATED; + +typedef struct __GLXattributeRecDEPRECATED { + GLuint mask; + + /* + ** Pixel storage state. Most of the pixel store mode state is kept + ** here and used by the client code to manage the packing and + ** unpacking of data sent to/received from the server. + */ + __GLXpixelStoreMode storePack, storeUnpack; + + /* + ** Vertex Array storage state. The vertex array component + ** state is stored here and is used to manage the packing of + ** DrawArrays data sent to the server. + */ + __GLXvertArrayStateDEPRECATED vertArray; +} __GLXattributeDEPRECATED; + +typedef struct __GLXvertexArrayPointerStateRec { + void (*proc)(const void *); + void (*mtex_proc)(GLenum, const void *); + const GLubyte *ptr; + GLsizei skip; + GLint size; + GLenum type; + GLsizei stride; +} __GLXvertexArrayPointerState; + +/** + * Define which entries of \c __GLXvertArrayState::arrays match which + * vertex arrays in the client-state vector. These are only the one-of + * arrays. See the \c __GLXvertArrayState::arrays documentation for more + * details. + * + * \sa __GLXvertArrayState + */ +enum { + edgeFlag_ARRAY, /**< \c GL_EDGE_FLAG_ARRAY */ + index_ARRAY, /**< \c GL_INDEX_ARRAY */ + fogCoord_ARRAY, /**< \c GL_FOG_COORD_ARRAY */ + secondaryColor_ARRAY, /**< \c GL_SECONDARY_COLOR_ARRAY */ + color_ARRAY, /**< \c GL_COLOR_ARRAY */ + normal_ARRAY, /**< \c GL_NORMAL_ARRAY */ + + /** + * \c GL_VERTEX_ARRAY \b must be last! All of the code for emitting arrays + * and array elements is written based on the assumption that the vertex + * array is last. + */ + vertex_ARRAY, + + __GLX_MAX_ARRAYS /**< Place holder entry. */ +}; + +#define ENABLE_ARRAY(state,a) \ + do { (state)->vertArray.enables |= (1U << (a ## _ARRAY)); } while( 0 ) +#define DISABLE_ARRAY(state,a) \ + do { (state)->vertArray.enables &= ~(1U << (a ## _ARRAY)); } while( 0 ) +#define IS_ARRAY_ENABLED_BY_INDEX(state, i) \ + (((state)->vertArray.enables & (1U << (i))) != 0) +#define IS_ARRAY_ENABLED(state, a) \ + IS_ARRAY_ENABLED_BY_INDEX(state, a ## _ARRAY) + +#define ENABLE_TEXARRAY(state,a) \ + do { (state)->vertArray.texture_enables |= (1U << a); } while( 0 ) +#define DISABLE_TEXARRAY(state,a) \ + do { (state)->vertArray.texture_enables &= ~(1U << a); } while( 0 ) +#define IS_TEXARRAY_ENABLED(state, a) \ + (((state)->vertArray.texture_enables & (1U << a)) != 0) + +/** + * Client-side vertex array state. + */ +typedef struct __GLXvertArrayStateRec { + /** + * Which client-side arrays are enabled? These are the flag bits for + * all of the non-texture coordinate arrays. + */ + GLuint enables; + + /** + * Which of the texture coordinate arrays are enabled? + */ + GLuint texture_enables; + + /** + * State for "one-of" arrays. These are the arrays, such as + * GL_COLOR_ARRAY or GL_FOG_COORD_ARRAY for which there is only one + * array. There are also "many-of" arrays, such as + * GL_TEXTURE_COORD_ARRAY. + */ + __GLXvertexArrayPointerState arrays[__GLX_MAX_ARRAYS]; + + __GLXvertexArrayPointerState texCoord[__GLX_MAX_TEXTURE_UNITS]; + + GLint maxElementsVertices; + GLint maxElementsIndices; + GLint activeTexture; +} __GLXvertArrayState; + +typedef struct __GLXattributeRec { + GLuint mask; + + /* + ** Pixel storage state. Most of the pixel store mode state is kept + ** here and used by the client code to manage the packing and + ** unpacking of data sent to/received from the server. + */ + __GLXpixelStoreMode storePack, storeUnpack; + + /* + ** Vertex Array storage state. The vertex array component + ** state is stored here and is used to manage the packing of + ** DrawArrays data sent to the server. + */ + __GLXvertArrayState vertArray; + + /** + * Is EXT_vertex_array / GL 1.1 DrawArrays protocol specifically + * disabled? + */ + GLboolean NoDrawArraysProtocol; +} __GLXattribute; + +typedef struct __GLXattributeMachineRec { + __GLXattribute *stack[__GL_CLIENT_ATTRIB_STACK_DEPTH]; + __GLXattribute **stackPointer; +} __GLXattributeMachine; + +/** + * GLX state that needs to be kept on the client. One of these records + * exist for each context that has been made current by this client. + */ +struct __GLXcontextRec { + /** + * \name Drawing command buffer. + * + * Drawing commands are packed into this buffer before being sent as a + * single GLX protocol request. The buffer is sent when it overflows or + * is flushed by \c __glXFlushRenderBuffer. \c pc is the next location + * in the buffer to be filled. \c limit is described above in the buffer + * slop discussion. + * + * Commands that require large amounts of data to be transfered will + * also use this buffer to hold a header that describes the large + * command. + * + * These must be the first 6 fields since they are static initialized + * in the dummy context in glxext.c + */ + /*@{*/ + GLubyte *buf; + GLubyte *pc; + GLubyte *limit; + GLubyte *bufEnd; + GLint bufSize; + /*@}*/ + + /** + * The XID of this rendering context. When the context is created a + * new XID is allocated. This is set to None when the context is + * destroyed but is still current to some thread. In this case the + * context will be freed on next MakeCurrent. + */ + XID xid; + + /** + * The XID of the \c shareList context. + */ + XID share_xid; + + /** + * Visual id. + * + * \deprecated + * This filed has been largely been replaced by the \c mode field, but + * the work is not quite done. + */ + VisualID vid; + + /** + * Screen number. + */ + GLint screen; + + /** + * \c GL_TRUE if the context was created with ImportContext, which + * means the server-side context was created by another X client. + */ + GLboolean imported; + + /** + * The context tag returned by MakeCurrent when this context is made + * current. This tag is used to identify the context that a thread has + * current so that proper server context management can be done. It is + * used for all context specific commands (i.e., \c Render, \c RenderLarge, + * \c WaitX, \c WaitGL, \c UseXFont, and \c MakeCurrent (for the old + * context)). + */ + GLXContextTag currentContextTag; + + /** + * \name Rendering mode + * + * The rendering mode is kept on the client as well as the server. + * When \c glRenderMode is called, the buffer associated with the + * previous rendering mode (feedback or select) is filled. + */ + /*@{*/ + GLenum renderMode; + GLfloat *feedbackBuf; + GLuint *selectBuf; + /*@}*/ + + /** + * This is \c GL_TRUE if the pixel unpack modes are such that an image + * can be unpacked from the clients memory by just copying. It may + * still be true that the server will have to do some work. This + * just promises that a straight copy will fetch the correct bytes. + */ + GLboolean fastImageUnpack; + + /** + * Fill newImage with the unpacked form of \c oldImage getting it + * ready for transport to the server. + */ + void (*fillImage)(__GLXcontext*, GLint, GLint, GLint, GLint, GLenum, + GLenum, const GLvoid*, GLubyte*, GLubyte*); + + /** + * \name Client side attribs. + */ + /*@{*/ + __GLXattributeDEPRECATED stateDEPRECATED; + __GLXattributeMachine attributes; + /*@}*/ + + /** + * Client side error code. This is set when client side gl API + * routines need to set an error because of a bad enumerant or + * running out of memory, etc. + */ + GLenum error; + + /** + * Whether this context does direct rendering. + */ + Bool isDirect; + + /** + * \c dpy of current display for this context. Will be \c NULL if not + * current to any display, or if this is the "dummy context". + */ + Display *currentDpy; + + /** + * The current drawable for this context. Will be None if this + * context is not current to any drawable. currentReadable is below. + */ + GLXDrawable currentDrawable; + + /** + * \name GL Constant Strings + * + * Constant strings that describe the server implementation + * These pertain to GL attributes, not to be confused with + * GLX versioning attributes. + */ + /*@{*/ + GLubyte *vendor; + GLubyte *renderer; + GLubyte *version; + GLubyte *extensions; + /*@}*/ + + /** + * Record the dpy this context was created on for later freeing + */ + Display *createDpy; + + /** + * Maximum small render command size. This is the smaller of 64k and + * the size of the above buffer. + */ + GLint maxSmallRenderCommandSize; + + /** + * Major opcode for the extension. Copied here so a lookup isn't + * needed. + */ + GLint majorOpcode; + +#ifdef GLX_DIRECT_RENDERING + /** + * Per context direct rendering interface functions and data. + */ + __DRIcontext driContext; +#endif + + /** + * \c GLXFBConfigID used to create this context. May be \c None. This + * field has been replaced by the \c mode field. + * + * \since Internal API version 20030317. + * + * \deprecated + * This filed has been largely been replaced by the \c mode field, but + * the work is not quite done. + */ + GLXFBConfigID fbconfigID; + + /** + * The current read-drawable for this context. Will be None if this + * context is not current to any drawable. + * + * \since Internal API version 20030606. + */ + GLXDrawable currentReadable; + + /** + * Pointer to client-state data that is private to libGL. This is only + * used for indirect rendering contexts. + * + * No internal API version change was made for this change. Client-side + * drivers should NEVER use this data or even care that it exists. + */ + void * client_state_private; + +#ifdef GLX_DIRECT_RENDERING + /** + * Pointer to the mode used to create this context. This field replaces + * the \c vid and \c fbconfigID fields. + * + * \since Internal API version 20031201. + */ + const __GLcontextModes * mode; +#endif /* GLX_DIRECT_RENDERING */ +}; + +#define __glXSetError(gc,code) \ + if (!(gc)->error) { \ + (gc)->error = code; \ + } + +extern void __glFreeAttributeState(__GLXcontext *); + +/************************************************************************/ + +/** + * The size of the largest drawing command known to the implementation + * that will use the GLXRender GLX command. In this case it is + * \c glPolygonStipple. + */ +#define __GLX_MAX_SMALL_RENDER_CMD_SIZE 156 + +/** + * To keep the implementation fast, the code uses a "limit" pointer + * to determine when the drawing command buffer is too full to hold + * another fixed size command. This constant defines the amount of + * space that must always be available in the drawing command buffer + * at all times for the implementation to work. It is important that + * the number be just large enough, but not so large as to reduce the + * efficacy of the buffer. The "+32" is just to keep the code working + * in case somebody counts wrong. + */ +#define __GLX_BUFFER_LIMIT_SIZE (__GLX_MAX_SMALL_RENDER_CMD_SIZE + 32) + +/** + * This implementation uses a smaller threshold for switching + * to the RenderLarge protocol than the protcol requires so that + * large copies don't occur. + */ +#define __GLX_RENDER_CMD_SIZE_LIMIT 4096 + +/** + * One of these records exists per screen of the display. It contains + * a pointer to the config data for that screen (if the screen supports GL). + */ +typedef struct __GLXscreenConfigsRec { + /** + * GLX visuals formated as \c __GLXvisualConfig structures. + */ + /*@{*/ + __GLXvisualConfig * old_configs; + int numOldConfigs; + /*@}*/ + + /** + * GLX extension string reported by the X-server. + */ + const char *serverGLXexts; + + /** + * GLX extension string to be reported to applications. This is the + * set of extensions that the application can actually use. + */ + char *effectiveGLXexts; + +#ifdef GLX_DIRECT_RENDERING + /** + * Per screen direct rendering interface functions and data. + */ + __DRIscreen driScreen; +#endif + + /** + * Linked list of configurations for this screen. This is intended to + * be a superset of \c old_configs. + */ + __GLcontextModes *configs; + /** + * Per-screen dynamic GLX extension tracking. The \c direct_support + * field only contains enough bits for 64 extensions. Should libGL + * ever need to track more than 64 GLX extensions, we can safely grow + * this field. The \c __GLXscreenConfigs structure is not used outside + * libGL. + */ + /*@{*/ + unsigned char direct_support[8]; + GLboolean ext_list_first_time; + /*@}*/ + +} __GLXscreenConfigs; + +/** + * Per display private data. One of these records exists for each display + * that is using the OpenGL (GLX) extension. + */ +struct __GLXdisplayPrivateRec { + /** + * Back pointer to the display + */ + Display *dpy; + + /** + * The \c majorOpcode is common to all connections to the same server. + * It is also copied into the context structure. + */ + int majorOpcode; + + /** + * \name Server Version + * + * Major and minor version returned by the server during initialization. + */ + /*@{*/ + int majorVersion, minorVersion; + /*@}*/ + + /** + * \name Storage for the servers GLX vendor and versions strings. + * + * These are the same for all screens on this display. These fields will + * be filled in on demand. + */ + /*@{*/ + char *serverGLXvendor; + char *serverGLXversion; + /*@}*/ + + /** + * Configurations of visuals for all screens on this display. + * Also, per screen data which now includes the server \c GLX_EXTENSION + * string. + */ + __GLXscreenConfigs *screenConfigs; + +#ifdef GLX_DIRECT_RENDERING + /** + * Per display direct rendering interface functions and data. + */ + __DRIdisplay driDisplay; +#endif +}; + +void __glXFreeContext(__GLXcontext*); + +extern GLubyte *__glXFlushRenderBuffer(__GLXcontext*, GLubyte*); + +extern void __glXSendLargeChunk(__GLXcontext *gc, GLint requestNumber, + GLint totalRequests, + const GLvoid * data, GLint dataLen); + +extern void __glXSendLargeCommand(__GLXcontext *, const GLvoid *, GLint, + const GLvoid *, GLint); + +/* Initialize the GLX extension for dpy */ +extern __GLXdisplayPrivate *__glXInitialize(Display*); + +/************************************************************************/ + +extern int __glXDebug; + +/* This is per-thread storage in an MT environment */ +#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS) +extern __GLXcontext *__glXGetCurrentContext(void); +extern void __glXSetCurrentContext(__GLXcontext *c); +#else +extern __GLXcontext *__glXcurrentContext; +#define __glXGetCurrentContext() __glXcurrentContext +#define __glXSetCurrentContext(gc) __glXcurrentContext = gc +#endif + + +/* +** Global lock for all threads in this address space using the GLX +** extension +*/ +#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS) +extern xmutex_rec __glXmutex; +#define __glXLock() xmutex_lock(&__glXmutex) +#define __glXUnlock() xmutex_unlock(&__glXmutex) +#else +#define __glXLock() +#define __glXUnlock() +#endif + +/* +** Setup for a command. Initialize the extension for dpy if necessary. +*/ +extern CARD8 __glXSetupForCommand(Display *dpy); + +/************************************************************************/ + +/* +** Data conversion and packing support. +*/ + +/* Return the size, in bytes, of some pixel data */ +extern GLint __glImageSize(GLint, GLint, GLint, GLenum, GLenum); + +/* Return the number of elements per group of a specified format*/ +extern GLint __glElementsPerGroup(GLenum format, GLenum type); + +/* Return the number of bytes per element, based on the element type (other +** than GL_BITMAP). +*/ +extern GLint __glBytesPerElement(GLenum type); + +/* Return the k value for a given map target */ +extern GLint __glEvalComputeK(GLenum); + +/* +** Fill the transport buffer with the data from the users buffer, +** applying some of the pixel store modes (unpack modes) to the data +** first. As a side effect of this call, the "modes" field is +** updated to contain the modes needed by the server to decode the +** sent data. +*/ +extern void __glFillImage(__GLXcontext*, GLint, GLint, GLint, GLint, GLenum, + GLenum, const GLvoid*, GLubyte*, GLubyte*); + +/* Copy map data with a stride into a packed buffer */ +extern void __glFillMap1f(GLint, GLint, GLint, const GLfloat *, GLubyte *); +extern void __glFillMap1d(GLint, GLint, GLint, const GLdouble *, GLubyte *); +extern void __glFillMap2f(GLint, GLint, GLint, GLint, GLint, + const GLfloat *, GLfloat *); +extern void __glFillMap2d(GLint, GLint, GLint, GLint, GLint, + const GLdouble *, GLdouble *); + +/* +** Empty an image out of the reply buffer into the clients memory applying +** the pack modes to pack back into the clients requested format. +*/ +extern void __glEmptyImage(__GLXcontext*, GLint, GLint, GLint, GLint, GLenum, + GLenum, const GLubyte *, GLvoid *); + + +/* +** Allocate and Initialize Vertex Array client state +*/ +extern void __glXInitVertexArrayState(__GLXcontext*); + +/* +** Inform the Server of the major and minor numbers and of the client +** libraries extension string. +*/ +extern void __glXClientInfo ( Display *dpy, int opcode ); + +/************************************************************************/ + +/* +** Declarations that should be in Xlib +*/ +#ifdef __GL_USE_OUR_PROTOTYPES +extern void _XFlush(Display*); +extern Status _XReply(Display*, xReply*, int, Bool); +extern void _XRead(Display*, void*, long); +extern void _XSend(Display*, const void*, long); +#endif + + +/* +** GLX_BUILT_IN_XMESA controls whether libGL has a built-in verions of +** Mesa that can render to non-GLX displays. +*/ +#ifdef GLX_BUILT_IN_XMESA +#define GLX_PREFIX(function) _real_##function +#else +#define GLX_PREFIX(function) function +#endif + + +extern void __glXInitializeVisualConfigFromTags( __GLcontextModes *config, + int count, const INT32 *bp, Bool tagged_only, Bool fbconfig_style_tags ); + +extern char *__glXInternalQueryServerString( Display *dpy, int opcode, + int screen, int name ); + +extern char *__glXstrdup(const char *str); + + +extern const char __glXGLClientVersion[]; +extern const char __glXGLClientExtensions[]; +extern char *__glXCombineExtensionStrings( const char *cext_string, + const char *sext_string ); + +/* Determine the internal API version */ +extern int __glXGetInternalVersion(void); + +/** + * Type of a pointer to \c __glXGetInternalVersion, as returned by + * \c glXGetProcAddress. + * + * \sa __glXGetInternalVersion, glXGetProcAddress + */ +typedef int (* PFNGLXGETINTERNALVERSIONPROC) ( void ); + +/** + * Type of a pointer to \c __glXWindowExists, as returned by + * \c glXGetProcAddress. + * + * \sa __glXWindowExists, glXGetProcAddress + */ +typedef Bool (* PFNGLXWINDOWEXISTSPROC) (Display *dpy, GLXDrawable draw); + +/* Get the unadjusted system time */ +extern int __glXGetUST( int64_t * ust ); + +/** + * Type of a pointer to \c __glXGetUST, as returned by \c glXGetProcAddress. + * + * \sa __glXGetUST, glXGetProcAddress + */ +typedef int (* PFNGLXGETUSTPROC) ( int64_t * ust ); + + +/** + * Type of pointer to \c __glXCreateContextModes, as returned by + * \c glXGetProcAddress. + * + * \sa _gl_context_modes_create, glXGetProcAddress + */ + +typedef __GLcontextModes * (* PFNGLXCREATECONTEXTMODES) ( unsigned count, + size_t minimum_bytes_per_struct ); + +#endif /* !__GLX_client_h__ */ diff --git a/src/mesa/drivers/dri/dri_client/imports/sarea.h b/src/mesa/drivers/dri/dri_client/imports/sarea.h new file mode 100644 index 00000000000..d4d83df930f --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/imports/sarea.h @@ -0,0 +1,94 @@ +/* $XFree86: xc/programs/Xserver/GL/dri/sarea.h,v 1.11 2002/10/30 12:52:03 alanh Exp $ */ +/** + * \file sarea.h + * SAREA definitions. + * + * \author Kevin E. Martin + * \author Jens Owen + * \author Rickard E. (Rik) Faith + */ + +/* + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* $XFree86: xc/programs/Xserver/GL/dri/sarea.h,v 1.11 2002/10/30 12:52:03 alanh Exp $ */ + +#ifndef _SAREA_H_ +#define _SAREA_H_ + +#include "xf86drm.h" + +/* SAREA area needs to be at least a page */ +#if defined(__alpha__) +#define SAREA_MAX 0x2000 +#elif defined(__ia64__) +#define SAREA_MAX 0x10000 /* 64kB */ +#else +/* Intel 830M driver needs at least 8k SAREA */ +#define SAREA_MAX 0x2000 +#endif + +#define SAREA_MAX_DRAWABLES 256 + +#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000 + +/** + * SAREA per drawable information. + * + * \sa _XF86DRISAREA. + */ +typedef struct _XF86DRISAREADrawable { + unsigned int stamp; + unsigned int flags; +} XF86DRISAREADrawableRec, *XF86DRISAREADrawablePtr; + +/** + * SAREA frame information. + * + * \sa _XF86DRISAREA. + */ +typedef struct _XF86DRISAREAFrame { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int fullscreen; +} XF86DRISAREAFrameRec, *XF86DRISAREAFramePtr; + +/** + * SAREA definition. + */ +typedef struct _XF86DRISAREA { + /** first thing is always the DRM locking structure */ + drmLock lock; + /** \todo Use readers/writer lock for drawable_lock */ + drmLock drawable_lock; + XF86DRISAREADrawableRec drawableTable[SAREA_MAX_DRAWABLES]; + XF86DRISAREAFrameRec frame; + drmContext dummy_context; +} XF86DRISAREARec, *XF86DRISAREAPtr; + +#endif diff --git a/src/mesa/drivers/dri/dri_client/imports/xf86drm.h b/src/mesa/drivers/dri/dri_client/imports/xf86drm.h new file mode 100644 index 00000000000..c9f10074981 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/imports/xf86drm.h @@ -0,0 +1,646 @@ +/** + * \file xf86drm.h + * OS-independent header for DRM user-level library interface. + * + * \author Rickard E. (Rik) Faith + */ + +/* + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h,v 1.26 2003/08/16 19:26:37 dawes Exp $ */ + +#ifndef _XF86DRM_H_ +#define _XF86DRM_H_ + + /* Defaults, if nothing set in xf86config */ +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 +/* Default /dev/dri directory permissions 0755 */ +#define DRM_DEV_DIRMODE \ + (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) + +#define DRM_DIR_NAME "/dev/dri" +#define DRM_DEV_NAME "%s/card%d" +#define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ + +#define DRM_ERR_NO_DEVICE (-1001) +#define DRM_ERR_NO_ACCESS (-1002) +#define DRM_ERR_NOT_ROOT (-1003) +#define DRM_ERR_INVALID (-1004) +#define DRM_ERR_NO_FD (-1005) + +#define DRM_AGP_NO_HANDLE 0 + +typedef unsigned long drmHandle, *drmHandlePtr; /**< To mapped regions */ +typedef unsigned int drmSize, *drmSizePtr; /**< For mapped regions */ +typedef void *drmAddress, **drmAddressPtr; /**< For mapped regions */ +typedef unsigned int drmContext, *drmContextPtr; /**< GLXContext handle */ +typedef unsigned int drmDrawable, *drmDrawablePtr; /**< Unused */ +typedef unsigned int drmMagic, *drmMagicPtr; /**< Magic for authentication */ + +/** + * Driver version information. + * + * \sa drmGetVersion() and drmSetVersion(). + */ +typedef struct _drmVersion { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel; /**< Patch level */ + int name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + int date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + int desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ +} drmVersion, *drmVersionPtr; + +typedef struct _drmStats { + unsigned long count; /**< Number of data */ + struct { + unsigned long value; /**< Value from kernel */ + const char *long_format; /**< Suggested format for long_name */ + const char *long_name; /**< Long name for value */ + const char *rate_format; /**< Suggested format for rate_name */ + const char *rate_name; /**< Short name for value per second */ + int isvalue; /**< True if value (vs. counter) */ + const char *mult_names; /**< Multiplier names (e.g., "KGM") */ + int mult; /**< Multiplier value (e.g., 1024) */ + int verbose; /**< Suggest only in verbose output */ + } data[15]; +} drmStatsT; + + + /* All of these enums *MUST* match with the + kernel implementation -- so do *NOT* + change them! (The drmlib implementation + will just copy the flags instead of + translating them.) */ +typedef enum { + DRM_FRAME_BUFFER = 0, /**< WC, no caching, no core dump */ + DRM_REGISTERS = 1, /**< no caching, no core dump */ + DRM_SHM = 2, /**< shared, cached */ + DRM_AGP = 3, /**< AGP/GART */ + DRM_SCATTER_GATHER = 4 /**< PCI scatter/gather */ +} drmMapType; + +typedef enum { + DRM_RESTRICTED = 0x0001, /**< Cannot be mapped to client-virtual */ + DRM_READ_ONLY = 0x0002, /**< Read-only in client-virtual */ + DRM_LOCKED = 0x0004, /**< Physical pages locked */ + DRM_KERNEL = 0x0008, /**< Kernel requires access */ + DRM_WRITE_COMBINING = 0x0010, /**< Use write-combining, if available */ + DRM_CONTAINS_LOCK = 0x0020, /**< SHM page that contains lock */ + DRM_REMOVABLE = 0x0040 /**< Removable mapping */ +} drmMapFlags; + +/** + * \warning These values *MUST* match drm.h + */ +typedef enum { + /** \name Flags for DMA buffer dispatch */ + /*@{*/ + DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note the buffer may not yet have been + * processed by the hardware -- getting a + * hardware lock with the hardware quiescent + * will ensure that the buffer has been + * processed. + */ + DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + /*@}*/ + + /** \name Flags for DMA buffer request */ + /*@{*/ + DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ + /*@}*/ +} drmDMAFlags; + +typedef enum { + DRM_PAGE_ALIGN = 0x01, + DRM_AGP_BUFFER = 0x02, + DRM_SG_BUFFER = 0x04 +} drmBufDescFlags; + +typedef enum { + DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ +} drmLockFlags; + +typedef enum { + DRM_CONTEXT_PRESERVED = 0x01, /**< This context is preserved and + never swapped. */ + DRM_CONTEXT_2DONLY = 0x02 /**< This context is for 2D rendering only. */ +} drmContextFlags, *drmContextFlagsPtr; + +typedef struct _drmBufDesc { + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ +} drmBufDesc, *drmBufDescPtr; + +typedef struct _drmBufInfo { + int count; /**< Number of buffers described in list */ + drmBufDescPtr list; /**< List of buffer descriptions */ +} drmBufInfo, *drmBufInfoPtr; + +typedef struct _drmBuf { + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + drmAddress address; /**< Address */ +} drmBuf, *drmBufPtr; + +/** + * Buffer mapping information. + * + * Used by drmMapBufs() and drmUnmapBufs() to store information about the + * mapped buffers. + */ +typedef struct _drmBufMap { + int count; /**< Number of buffers mapped */ + drmBufPtr list; /**< Buffers */ +} drmBufMap, *drmBufMapPtr; + +typedef struct _drmLock { + volatile unsigned int lock; + char padding[60]; + /* This is big enough for most current (and future?) architectures: + DEC Alpha: 32 bytes + Intel Merced: ? + Intel P5/PPro/PII/PIII: 32 bytes + Intel StrongARM: 32 bytes + Intel i386/i486: 16 bytes + MIPS: 32 bytes (?) + Motorola 68k: 16 bytes + Motorola PowerPC: 32 bytes + Sun SPARC: 32 bytes + */ +} drmLock, *drmLockPtr; + +/** + * Indices here refer to the offset into + * list in drmBufInfo + */ +typedef struct _drmDMAReq { + drmContext context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_list; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send, in bytes */ + drmDMAFlags flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size of buffers requested */ + int *request_list; /**< Buffer information */ + int *request_sizes; /**< Minimum acceptable sizes */ + int granted_count; /**< Number of buffers granted at this size */ +} drmDMAReq, *drmDMAReqPtr; + +typedef struct _drmRegion { + drmHandle handle; + unsigned int offset; + drmSize size; + drmAddress map; +} drmRegion, *drmRegionPtr; + +typedef struct _drmTextureRegion { + unsigned char next; + unsigned char prev; + unsigned char in_use; + unsigned char padding; /**< Explicitly pad this out */ + unsigned int age; +} drmTextureRegion, *drmTextureRegionPtr; + + +typedef struct _drmClipRect { + unsigned short x1; /* Upper left: inclusive */ + unsigned short y1; + unsigned short x2; /* Lower right: exclusive */ + unsigned short y2; +} drmClipRect, *drmClipRectPtr; + + +typedef enum { + DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ +} drmVBlankSeqType; + +typedef struct _drmVBlankReq { + drmVBlankSeqType type; + unsigned int sequence; + unsigned long signal; +} drmVBlankReq, *drmVBlankReqPtr; + +typedef struct _drmVBlankReply { + drmVBlankSeqType type; + unsigned int sequence; + long tval_sec; + long tval_usec; +} drmVBlankReply, *drmVBlankReplyPtr; + +typedef union _drmVBlank { + drmVBlankReq request; + drmVBlankReply reply; +} drmVBlank, *drmVBlankPtr; + +typedef struct _drmSetVersion { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +} drmSetVersion, *drmSetVersionPtr; + + +#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) + +#define DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */ +#define DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */ + +#if defined(__GNUC__) && (__GNUC__ >= 2) +# if defined(__i386) || defined(__AMD64__) + /* Reflect changes here to drmP.h */ +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + int __dummy; /* Can't mark eax as clobbered */ \ + __asm__ __volatile__( \ + "lock ; cmpxchg %4,%1\n\t" \ + "setnz %0" \ + : "=d" (__ret), \ + "=m" (__drm_dummy_lock(lock)), \ + "=a" (__dummy) \ + : "2" (old), \ + "r" (new)); \ + } while (0) + +#elif defined(__alpha__) + +#define DRM_CAS(lock, old, new, ret) \ + do { \ + int old32; \ + int cur32; \ + __asm__ __volatile__( \ + " mb\n" \ + " zap %4, 0xF0, %0\n" \ + " ldl_l %1, %2\n" \ + " zap %1, 0xF0, %1\n" \ + " cmpeq %0, %1, %1\n" \ + " beq %1, 1f\n" \ + " bis %5, %5, %1\n" \ + " stl_c %1, %2\n" \ + "1: xor %1, 1, %1\n" \ + " stl %1, %3" \ + : "+r" (old32), \ + "+&r" (cur32), \ + "=m" (__drm_dummy_lock(lock)),\ + "=m" (ret) \ + : "r" (old), \ + "r" (new)); \ + } while(0) + +#elif defined(__sparc__) + +#define DRM_CAS(lock,old,new,__ret) \ +do { register unsigned int __old __asm("o0"); \ + register unsigned int __new __asm("o1"); \ + register volatile unsigned int *__lock __asm("o2"); \ + __old = old; \ + __new = new; \ + __lock = (volatile unsigned int *)lock; \ + __asm__ __volatile__( \ + /*"cas [%2], %3, %0"*/ \ + ".word 0xd3e29008\n\t" \ + /*"membar #StoreStore | #StoreLoad"*/ \ + ".word 0x8143e00a" \ + : "=&r" (__new) \ + : "0" (__new), \ + "r" (__lock), \ + "r" (__old) \ + : "memory"); \ + __ret = (__new != __old); \ +} while(0) + +#elif defined(__ia64__) + +#ifdef __INTEL_COMPILER +/* this currently generates bad code (missing stop bits)... */ +#include + +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + unsigned long __result, __old = (old) & 0xffffffff; \ + __mf(); \ + __result = _InterlockedCompareExchange_acq(&__drm_dummy_lock(lock), (new), __old);\ + __ret = (__result) != (__old); \ +/* __ret = (__sync_val_compare_and_swap(&__drm_dummy_lock(lock), \ + (old), (new)) \ + != (old)); */\ + } while (0) + +#else +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + unsigned int __result, __old = (old); \ + __asm__ __volatile__( \ + "mf\n" \ + "mov ar.ccv=%2\n" \ + ";;\n" \ + "cmpxchg4.acq %0=%1,%3,ar.ccv" \ + : "=r" (__result), "=m" (__drm_dummy_lock(lock)) \ + : "r" ((unsigned long)__old), "r" (new) \ + : "memory"); \ + __ret = (__result) != (__old); \ + } while (0) + +#endif + +#elif defined(__powerpc__) + +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + __asm__ __volatile__( \ + "sync;" \ + "0: lwarx %0,0,%1;" \ + " xor. %0,%3,%0;" \ + " bne 1f;" \ + " stwcx. %2,0,%1;" \ + " bne- 0b;" \ + "1: " \ + "sync;" \ + : "=&r"(__ret) \ + : "r"(lock), "r"(new), "r"(old) \ + : "cr0", "memory"); \ + } while (0) + +#endif /* architecture */ +#endif /* __GNUC__ >= 2 */ + +#ifndef DRM_CAS +#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */ +#endif + +#if defined(__alpha__) || defined(__powerpc__) +#define DRM_CAS_RESULT(_result) int _result +#else +#define DRM_CAS_RESULT(_result) char _result +#endif + +#define DRM_LIGHT_LOCK(fd,lock,context) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \ + if (__ret) drmGetLock(fd,context,0); \ + } while(0) + + /* This one counts fast locks -- for + benchmarking only. */ +#define DRM_LIGHT_LOCK_COUNT(fd,lock,context,count) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \ + if (__ret) drmGetLock(fd,context,0); \ + else ++count; \ + } while(0) + +#define DRM_LOCK(fd,lock,context,flags) \ + do { \ + if (flags) drmGetLock(fd,context,flags); \ + else DRM_LIGHT_LOCK(fd,lock,context); \ + } while(0) + +#define DRM_UNLOCK(fd,lock,context) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,DRM_LOCK_HELD|context,context,__ret); \ + if (__ret) drmUnlock(fd,context); \ + } while(0) + + /* Simple spin locks */ +#define DRM_SPINLOCK(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + do { \ + DRM_CAS(spin,0,val,__ret); \ + if (__ret) while ((spin)->lock); \ + } while (__ret); \ + } while(0) + +#define DRM_SPINLOCK_TAKE(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + int cur; \ + do { \ + cur = (*spin).lock; \ + DRM_CAS(spin,cur,val,__ret); \ + } while (__ret); \ + } while(0) + +#define DRM_SPINLOCK_COUNT(spin,val,count,__ret) \ + do { \ + int __i; \ + __ret = 1; \ + for (__i = 0; __ret && __i < count; __i++) { \ + DRM_CAS(spin,0,val,__ret); \ + if (__ret) for (;__i < count && (spin)->lock; __i++); \ + } \ + } while(0) + +#define DRM_SPINUNLOCK(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + if ((*spin).lock == val) { /* else server stole lock */ \ + do { \ + DRM_CAS(spin,val,0,__ret); \ + } while (__ret); \ + } \ + } while(0) + +/* General user-level programmer's API: unprivileged */ +extern int drmAvailable(void); +extern int drmOpen(const char *name, const char *busid); +extern int drmClose(int fd); +extern drmVersionPtr drmGetVersion(int fd); +extern drmVersionPtr drmGetLibVersion(int fd); +extern void drmFreeVersion(drmVersionPtr); +extern int drmGetMagic(int fd, drmMagicPtr magic); +extern char *drmGetBusid(int fd); +extern int drmGetInterruptFromBusID(int fd, int busnum, int devnum, + int funcnum); +extern int drmGetMap(int fd, int idx, drmHandle *offset, + drmSize *size, drmMapType *type, + drmMapFlags *flags, drmHandle *handle, + int *mtrr); +extern int drmGetClient(int fd, int idx, int *auth, int *pid, + int *uid, unsigned long *magic, + unsigned long *iocs); +extern int drmGetStats(int fd, drmStatsT *stats); +extern int drmSetInterfaceVersion(int fd, drmSetVersion *version); +extern int drmCommandNone(int fd, unsigned long drmCommandIndex); +extern int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); +extern int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); +extern int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); + +/* General user-level programmer's API: X server (root) only */ +extern void drmFreeBusid(const char *busid); +extern int drmSetBusid(int fd, const char *busid); +extern int drmAuthMagic(int fd, drmMagic magic); +extern int drmAddMap(int fd, + drmHandle offset, + drmSize size, + drmMapType type, + drmMapFlags flags, + drmHandlePtr handle); +extern int drmRmMap(int fd, drmHandle handle); +extern int drmAddContextPrivateMapping(int fd, drmContext ctx_id, + drmHandle handle); + +extern int drmAddBufs(int fd, int count, int size, + drmBufDescFlags flags, + int agp_offset); +extern int drmMarkBufs(int fd, double low, double high); +extern int drmCreateContext(int fd, drmContextPtr handle); +extern int drmSetContextFlags(int fd, drmContext context, + drmContextFlags flags); +extern int drmGetContextFlags(int fd, drmContext context, + drmContextFlagsPtr flags); +extern int drmAddContextTag(int fd, drmContext context, void *tag); +extern int drmDelContextTag(int fd, drmContext context); +extern void *drmGetContextTag(int fd, drmContext context); +extern drmContextPtr drmGetReservedContextList(int fd, int *count); +extern void drmFreeReservedContextList(drmContextPtr); +extern int drmSwitchToContext(int fd, drmContext context); +extern int drmDestroyContext(int fd, drmContext handle); +extern int drmCreateDrawable(int fd, drmDrawablePtr handle); +extern int drmDestroyDrawable(int fd, drmDrawable handle); +extern int drmCtlInstHandler(int fd, int irq); +extern int drmCtlUninstHandler(int fd); +extern int drmInstallSIGIOHandler(int fd, + void (*f)(int fd, + void *oldctx, + void *newctx)); +extern int drmRemoveSIGIOHandler(int fd); + +/* General user-level programmer's API: authenticated client and/or X */ +extern int drmMap(int fd, + drmHandle handle, + drmSize size, + drmAddressPtr address); +extern int drmUnmap(drmAddress address, drmSize size); +extern drmBufInfoPtr drmGetBufInfo(int fd); +extern drmBufMapPtr drmMapBufs(int fd); +extern int drmUnmapBufs(drmBufMapPtr bufs); +extern int drmDMA(int fd, drmDMAReqPtr request); +extern int drmFreeBufs(int fd, int count, int *list); +extern int drmGetLock(int fd, + drmContext context, + drmLockFlags flags); +extern int drmUnlock(int fd, drmContext context); +extern int drmFinish(int fd, int context, drmLockFlags flags); +extern int drmGetContextPrivateMapping(int fd, drmContext ctx_id, + drmHandlePtr handle); + +/* AGP/GART support: X server (root) only */ +extern int drmAgpAcquire(int fd); +extern int drmAgpRelease(int fd); +extern int drmAgpEnable(int fd, unsigned long mode); +extern int drmAgpAlloc(int fd, unsigned long size, + unsigned long type, unsigned long *address, + unsigned long *handle); +extern int drmAgpFree(int fd, unsigned long handle); +extern int drmAgpBind(int fd, unsigned long handle, + unsigned long offset); +extern int drmAgpUnbind(int fd, unsigned long handle); + +/* AGP/GART info: authenticated client and/or X */ +extern int drmAgpVersionMajor(int fd); +extern int drmAgpVersionMinor(int fd); +extern unsigned long drmAgpGetMode(int fd); +extern unsigned long drmAgpBase(int fd); /* Physical location */ +extern unsigned long drmAgpSize(int fd); /* Bytes */ +extern unsigned long drmAgpMemoryUsed(int fd); +extern unsigned long drmAgpMemoryAvail(int fd); +extern unsigned int drmAgpVendorId(int fd); +extern unsigned int drmAgpDeviceId(int fd); + +/* PCI scatter/gather support: X server (root) only */ +extern int drmScatterGatherAlloc(int fd, unsigned long size, + unsigned long *handle); +extern int drmScatterGatherFree(int fd, unsigned long handle); + +extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); + +/* Support routines */ +extern int drmError(int err, const char *label); +extern void *drmMalloc(int size); +extern void drmFree(void *pt); + +/* Hash table routines */ +extern void *drmHashCreate(void); +extern int drmHashDestroy(void *t); +extern int drmHashLookup(void *t, unsigned long key, void **value); +extern int drmHashInsert(void *t, unsigned long key, void *value); +extern int drmHashDelete(void *t, unsigned long key); +extern int drmHashFirst(void *t, unsigned long *key, void **value); +extern int drmHashNext(void *t, unsigned long *key, void **value); + +/* PRNG routines */ +extern void *drmRandomCreate(unsigned long seed); +extern int drmRandomDestroy(void *state); +extern unsigned long drmRandom(void *state); +extern double drmRandomDouble(void *state); + +/* Skip list routines */ + +extern void *drmSLCreate(void); +extern int drmSLDestroy(void *l); +extern int drmSLLookup(void *l, unsigned long key, void **value); +extern int drmSLInsert(void *l, unsigned long key, void *value); +extern int drmSLDelete(void *l, unsigned long key); +extern int drmSLNext(void *l, unsigned long *key, void **value); +extern int drmSLFirst(void *l, unsigned long *key, void **value); +extern void drmSLDump(void *l); +extern int drmSLLookupNeighbors(void *l, unsigned long key, + unsigned long *prev_key, void **prev_value, + unsigned long *next_key, void **next_value); + +#endif diff --git a/src/mesa/drivers/dri/dri_client/xf86dri.h b/src/mesa/drivers/dri/dri_client/xf86dri.h new file mode 100644 index 00000000000..013f5b32d5d --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/xf86dri.h @@ -0,0 +1,221 @@ +/* $XFree86: xc/lib/GL/dri/xf86dri.h,v 1.8 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin + * Jens Owen + * Rickard E. (Rik) Faith + * + */ + +#ifndef _XF86DRI_H_ +#define _XF86DRI_H_ + +#include +#include + +#define X_XF86DRIQueryVersion 0 +#define X_XF86DRIQueryDirectRenderingCapable 1 +#define X_XF86DRIOpenConnection 2 +#define X_XF86DRICloseConnection 3 +#define X_XF86DRIGetClientDriverName 4 +#define X_XF86DRICreateContext 5 +#define X_XF86DRIDestroyContext 6 +#define X_XF86DRICreateDrawable 7 +#define X_XF86DRIDestroyDrawable 8 +#define X_XF86DRIGetDrawableInfo 9 +#define X_XF86DRIGetDeviceInfo 10 +#define X_XF86DRIAuthConnection 11 +#define X_XF86DRIOpenFullScreen 12 /* Deprecated */ +#define X_XF86DRICloseFullScreen 13 /* Deprecated */ + +#define XF86DRINumberEvents 0 + +#define XF86DRIClientNotLocal 0 +#define XF86DRIOperationNotSupported 1 +#define XF86DRINumberErrors (XF86DRIOperationNotSupported + 1) + +/* Warning : Do not change XF86DRIClipRect without changing the kernel + * structure! */ +typedef struct _XF86DRIClipRect { + unsigned short x1; /* Upper left: inclusive */ + unsigned short y1; + unsigned short x2; /* Lower right: exclusive */ + unsigned short y2; +} XF86DRIClipRectRec, *XF86DRIClipRectPtr; + +#ifndef _XF86DRI_SERVER_ + +_XFUNCPROTOBEGIN + +Bool XF86DRIQueryExtension( +#if NeedFunctionPrototypes + Display* /* dpy */, + int* /* event_base */, + int* /* error_base */ +#endif +); + +Bool XF86DRIQueryVersion( +#if NeedFunctionPrototypes + Display* /* dpy */, + int* /* majorVersion */, + int* /* minorVersion */, + int* /* patchVersion */ +#endif +); + +Bool XF86DRIQueryDirectRenderingCapable( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + Bool* /* isCapable */ +#endif +); + +Bool XF86DRIOpenConnection( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + drmHandlePtr /* hSAREA */, + char** /* busIDString */ +#endif +); + +Bool XF86DRIAuthConnection( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + drmMagic /* magic */ +#endif +); + +Bool XF86DRICloseConnection( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */ +#endif +); + +Bool XF86DRIGetClientDriverName( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + int* /* ddxDriverMajorVersion */, + int* /* ddxDriverMinorVersion */, + int* /* ddxDriverPatchVersion */, + char** /* clientDriverName */ +#endif +); + +Bool XF86DRICreateContext( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + Visual* /* visual */, + XID* /* ptr to returned context id */, + drmContextPtr /* hHWContext */ +#endif +); + +Bool XF86DRICreateContextWithConfig( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + int /* visual ID / fbconfig ID */, + XID* /* ptr to returned context id */, + drmContextPtr /* hHWContext */ +#endif +); + +Bool XF86DRIDestroyContext( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + XID /* context id */ +#endif +); + +Bool XF86DRICreateDrawable( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + Drawable /* drawable */, + drmDrawablePtr /* hHWDrawable */ +#endif +); + +Bool XF86DRIDestroyDrawable( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + Drawable /* drawable */ +#endif +); + +Bool XF86DRIGetDrawableInfo( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + Drawable /* drawable */, + unsigned int* /* index */, + unsigned int* /* stamp */, + int* /* X */, + int* /* Y */, + int* /* W */, + int* /* H */, + int* /* numClipRects */, + XF86DRIClipRectPtr*,/* pClipRects */ + int* /* backX */, + int* /* backY */, + int* /* numBackClipRects */, + XF86DRIClipRectPtr* /* pBackClipRects */ +#endif +); + +Bool XF86DRIGetDeviceInfo( +#if NeedFunctionPrototypes + Display* /* dpy */, + int /* screen */, + drmHandlePtr /* hFrameBuffer */, + int* /* fbOrigin */, + int* /* fbSize */, + int* /* fbStride */, + int* /* devPrivateSize */, + void** /* pDevPrivate */ +#endif +); + +_XFUNCPROTOEND + +#endif /* _XF86DRI_SERVER_ */ + +#endif /* _XF86DRI_H_ */ + diff --git a/src/mesa/drivers/dri/dri_client/xf86dristr.h b/src/mesa/drivers/dri/dri_client/xf86dristr.h new file mode 100644 index 00000000000..ac05b183b3c --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/xf86dristr.h @@ -0,0 +1,343 @@ +/* $XFree86: xc/lib/GL/dri/xf86dristr.h,v 1.10 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin + * Jens Owen + * Rickard E. (Rik) Fiath + * + */ + +#ifndef _XF86DRISTR_H_ +#define _XF86DRISTR_H_ + +#include "xf86dri.h" + +#define XF86DRINAME "XFree86-DRI" + +/* The DRI version number. This was originally set to be the same of the + * XFree86 version number. However, this version is really indepedent of + * the XFree86 version. + * + * Version History: + * 4.0.0: Original + * 4.0.1: Patch to bump clipstamp when windows are destroyed, 28 May 02 + * 4.1.0: Add transition from single to multi in DRMInfo rec, 24 Jun 02 + */ +#define XF86DRI_MAJOR_VERSION 4 +#define XF86DRI_MINOR_VERSION 1 +#define XF86DRI_PATCH_VERSION 0 + +typedef struct _XF86DRIQueryVersion { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIQueryVersion */ + CARD16 length B16; +} xXF86DRIQueryVersionReq; +#define sz_xXF86DRIQueryVersionReq 4 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD16 majorVersion B16; /* major version of DRI protocol */ + CARD16 minorVersion B16; /* minor version of DRI protocol */ + CARD32 patchVersion B32; /* patch version of DRI protocol */ + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIQueryVersionReply; +#define sz_xXF86DRIQueryVersionReply 32 + +typedef struct _XF86DRIQueryDirectRenderingCapable { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* X_DRIQueryDirectRenderingCapable */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIQueryDirectRenderingCapableReq; +#define sz_xXF86DRIQueryDirectRenderingCapableReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + BOOL isCapable; + BOOL pad2; + BOOL pad3; + BOOL pad4; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; + CARD32 pad9 B32; +} xXF86DRIQueryDirectRenderingCapableReply; +#define sz_xXF86DRIQueryDirectRenderingCapableReply 32 + +typedef struct _XF86DRIOpenConnection { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIOpenConnectionReq; +#define sz_xXF86DRIOpenConnectionReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hSAREALow B32; + CARD32 hSAREAHigh B32; + CARD32 busIdStringLength B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xXF86DRIOpenConnectionReply; +#define sz_xXF86DRIOpenConnectionReply 32 + +typedef struct _XF86DRIAuthConnection { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; + CARD32 magic B32; +} xXF86DRIAuthConnectionReq; +#define sz_xXF86DRIAuthConnectionReq 12 + +typedef struct { + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 authenticated B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIAuthConnectionReply; +#define zx_xXF86DRIAuthConnectionReply 32 + +typedef struct _XF86DRICloseConnection { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRICloseConnectionReq; +#define sz_xXF86DRICloseConnectionReq 8 + +typedef struct _XF86DRIGetClientDriverName { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetClientDriverName */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetClientDriverNameReq; +#define sz_xXF86DRIGetClientDriverNameReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 ddxDriverMajorVersion B32; + CARD32 ddxDriverMinorVersion B32; + CARD32 ddxDriverPatchVersion B32; + CARD32 clientDriverNameLength B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIGetClientDriverNameReply; +#define sz_xXF86DRIGetClientDriverNameReply 32 + +typedef struct _XF86DRICreateContext { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 visual B32; + CARD32 context B32; +} xXF86DRICreateContextReq; +#define sz_xXF86DRICreateContextReq 16 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWContext B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateContextReply; +#define sz_xXF86DRICreateContextReply 32 + +typedef struct _XF86DRIDestroyContext { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 context B32; +} xXF86DRIDestroyContextReq; +#define sz_xXF86DRIDestroyContextReq 12 + +typedef struct _XF86DRICreateDrawable { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICreateDrawableReq; +#define sz_xXF86DRICreateDrawableReq 12 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWDrawable B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateDrawableReply; +#define sz_xXF86DRICreateDrawableReply 32 + +typedef struct _XF86DRIDestroyDrawable { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIDestroyDrawableReq; +#define sz_xXF86DRIDestroyDrawableReq 12 + +typedef struct _XF86DRIGetDrawableInfo { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDrawableInfo */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIGetDrawableInfoReq; +#define sz_xXF86DRIGetDrawableInfoReq 12 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 drawableTableIndex B32; + CARD32 drawableTableStamp B32; + INT16 drawableX B16; + INT16 drawableY B16; + INT16 drawableWidth B16; + INT16 drawableHeight B16; + CARD32 numClipRects B32; + INT16 backX B16; + INT16 backY B16; + CARD32 numBackClipRects B32; +} xXF86DRIGetDrawableInfoReply; + +#define sz_xXF86DRIGetDrawableInfoReply 36 + + +typedef struct _XF86DRIGetDeviceInfo { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDeviceInfo */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetDeviceInfoReq; +#define sz_xXF86DRIGetDeviceInfoReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hFrameBufferLow B32; + CARD32 hFrameBufferHigh B32; + CARD32 framebufferOrigin B32; + CARD32 framebufferSize B32; + CARD32 framebufferStride B32; + CARD32 devPrivateSize B32; +} xXF86DRIGetDeviceInfoReply; +#define sz_xXF86DRIGetDeviceInfoReply 32 + +typedef struct _XF86DRIOpenFullScreen { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIOpenFullScreenReq; +#define sz_xXF86DRIOpenFullScreenReq 12 + +typedef struct { + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 isFullScreen B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIOpenFullScreenReply; +#define sz_xXF86DRIOpenFullScreenReply 32 + +typedef struct _XF86DRICloseFullScreen { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICloseFullScreenReq; +#define sz_xXF86DRICloseFullScreenReq 12 + +typedef struct { + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xXF86DRICloseFullScreenReply; +#define sz_xXF86DRICloseFullScreenReply 32 + + +#endif /* _XF86DRISTR_H_ */ diff --git a/src/mesa/drivers/dri/dri_client/xf86drm.c b/src/mesa/drivers/dri/dri_client/xf86drm.c new file mode 100644 index 00000000000..23750b9ca55 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/xf86drm.c @@ -0,0 +1,2326 @@ +/** + * \file xf86drm.c + * User-level interface to DRM device + * + * \author Rickard E. (Rik) Faith + * \author Kevin E. Martin + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drm.c,v 1.36 2003/08/24 17:35:35 tsi Exp $ */ + +#ifdef XFree86Server +# include "xf86.h" +# include "xf86_OSproc.h" +# include "drm.h" +# include "xf86_ansic.h" +# define _DRM_MALLOC xalloc +# define _DRM_FREE xfree +# ifndef XFree86LOADER +# include +# endif +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define stat_t struct stat +# include +# include +# include +# include +# ifdef DRM_USE_MALLOC +# define _DRM_MALLOC malloc +# define _DRM_FREE free +extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *); +extern int xf86RemoveSIGIOHandler(int fd); +# else +# include +# define _DRM_MALLOC Xmalloc +# define _DRM_FREE Xfree +# endif +# include "drm.h" +#endif + +/* No longer needed with CVS kernel modules on alpha +#if defined(__alpha__) && defined(__linux__) +extern unsigned long _bus_base(void); +#define BUS_BASE _bus_base() +#endif +*/ + +/* Not all systems have MAP_FAILED defined */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include "xf86drm.h" + +#ifdef __FreeBSD__ +#define DRM_MAJOR 145 +#endif + +#ifdef __NetBSD__ +#define DRM_MAJOR 34 +#endif + +# ifdef __OpenBSD__ +# define DRM_MAJOR 81 +# endif + +#ifndef DRM_MAJOR +#define DRM_MAJOR 226 /* Linux */ +#endif + +#ifndef DRM_MAX_MINOR +#define DRM_MAX_MINOR 16 +#endif + +#ifdef __linux__ +#include /* for makedev() */ +#endif + +#ifndef makedev + /* This definition needs to be changed on + some systems if dev_t is a structure. + If there is a header file we can get it + from, there would be best. */ +#define makedev(x,y) ((dev_t)(((x) << 8) | (y))) +#endif + +#define DRM_MSG_VERBOSITY 3 + +/** + * Output a message to stderr. + * + * \param format printf() like format string. + * + * \internal + * This function is a wrapper around vfprintf(). + */ +static void +drmMsg(const char *format, ...) +{ + va_list ap; + +#ifndef XFree86Server + const char *env; + if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) +#endif + { + va_start(ap, format); +#ifdef XFree86Server + xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); +#else + vfprintf(stderr, format, ap); +#endif + va_end(ap); + } +} + +static void *drmHashTable = NULL; /* Context switch callbacks */ + +typedef struct drmHashEntry { + int fd; + void (*f)(int, void *, void *); + void *tagTable; +} drmHashEntry; + +void *drmMalloc(int size) +{ + void *pt; + if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size); + return pt; +} + +void drmFree(void *pt) +{ + if (pt) _DRM_FREE(pt); +} + +/* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */ +static char *drmStrdup(const char *s) +{ + char *retval = NULL; + + if (s) { + retval = _DRM_MALLOC(strlen(s)+1); + strcpy(retval, s); + } + return retval; +} + + +static unsigned long drmGetKeyFromFd(int fd) +{ + stat_t st; + + st.st_rdev = 0; + fstat(fd, &st); + return st.st_rdev; +} + +static drmHashEntry *drmGetEntry(int fd) +{ + unsigned long key = drmGetKeyFromFd(fd); + void *value; + drmHashEntry *entry; + + if (!drmHashTable) drmHashTable = drmHashCreate(); + + if (drmHashLookup(drmHashTable, key, &value)) { + entry = drmMalloc(sizeof(*entry)); + entry->fd = fd; + entry->f = NULL; + entry->tagTable = drmHashCreate(); + drmHashInsert(drmHashTable, key, entry); + } else { + entry = value; + } + return entry; +} + +/** + * Compare two busid strings + * + * \param first + * \param second + * + * \return 1 if matched. + * + * \internal + * This function compares two bus ID strings. It understands the older + * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is + * domain, b is bus, d is device, f is function. + */ +static int drmMatchBusID(const char *id1, const char *id2) +{ + /* First, check if the IDs are exactly the same */ + if (strcasecmp(id1, id2) == 0) + return 1; + + /* Try to match old/new-style PCI bus IDs. */ + if (strncasecmp(id1, "pci", 3) == 0) { + int o1, b1, d1, f1; + int o2, b2, d2, f2; + int ret; + + ret = sscanf(id1, "pci:%04x:%02x:%02x.%d", &o1, &b1, &d1, &f1); + if (ret != 4) { + o1 = 0; + ret = sscanf(id1, "PCI:%d:%d:%d", &b1, &d1, &f1); + if (ret != 3) + return 0; + } + + ret = sscanf(id2, "pci:%04x:%02x:%02x.%d", &o2, &b2, &d2, &f2); + if (ret != 4) { + o2 = 0; + ret = sscanf(id2, "PCI:%d:%d:%d", &b2, &d2, &f2); + if (ret != 3) + return 0; + } + + if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) + return 0; + else + return 1; + } + return 0; +} + +/** + * Open the DRM device, creating it if necessary. + * + * \param dev major and minor numbers of the device. + * \param minor minor number of the device. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * Assembles the device name from \p minor and opens it, creating the device + * special file node with the major and minor numbers specified by \p dev and + * parent directory if necessary and was called by root. + */ +static int drmOpenDevice(long dev, int minor) +{ + stat_t st; + char buf[64]; + int fd; + mode_t devmode = DRM_DEV_MODE; + int isroot = !geteuid(); +#if defined(XFree86Server) + uid_t user = DRM_DEV_UID; + gid_t group = DRM_DEV_GID; +#endif + + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + drmMsg("drmOpenDevice: node name is %s\n", buf); + +#if defined(XFree86Server) + devmode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE; + devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); + group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID; +#endif + + if (stat(DRM_DIR_NAME, &st)) { + if (!isroot) return DRM_ERR_NOT_ROOT; + mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); + chown(DRM_DIR_NAME, 0, 0); /* root:root */ + chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); + } + + /* Check if the device node exists and create it if necessary. */ + if (stat(buf, &st)) { + if (!isroot) return DRM_ERR_NOT_ROOT; + remove(buf); + mknod(buf, S_IFCHR | devmode, dev); + } +#if defined(XFree86Server) + chown(buf, user, group); + chmod(buf, devmode); +#endif + + fd = open(buf, O_RDWR, 0); + drmMsg("drmOpenDevice: open result is %d, (%s)\n", + fd, fd < 0 ? strerror(errno) : "OK"); + if (fd >= 0) return fd; + + /* Check if the device node is not what we expect it to be, and recreate it + * and try again if so. + */ + if (st.st_rdev != dev) { + if (!isroot) return DRM_ERR_NOT_ROOT; + remove(buf); + mknod(buf, S_IFCHR | devmode, dev); +#if defined(XFree86Server) + chown(buf, user, group); + chmod(buf, devmode); +#endif + } + fd = open(buf, O_RDWR, 0); + drmMsg("drmOpenDevice: open result is %d, (%s)\n", + fd, fd < 0 ? strerror(errno) : "OK"); + if (fd >= 0) return fd; + + drmMsg("drmOpenDevice: Open failed\n"); + remove(buf); + return -errno; +} + + +/** + * Open the DRM device + * + * \param minor device minor number. + * \param create allow to create the device if set. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * Calls drmOpenDevice() if \p create is set, otherwise assembles the device + * name from \p minor and opens it. + */ +static int drmOpenMinor(int minor, int create) +{ + int fd; + char buf[64]; + + if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor); + + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd; + return -errno; +} + + +/** + * Determine whether the DRM kernel driver has been loaded. + * + * \return 1 if the DRM driver is loaded, 0 otherwise. + * + * \internal + * Determine the presence of the kernel driver by attempting to open the 0 + * minor and get version information. For backward compatibility with older + * Linux implementations, /proc/dri is also checked. + */ +int drmAvailable(void) +{ + drmVersionPtr version; + int retval = 0; + int fd; + + if ((fd = drmOpenMinor(0, 1)) < 0) { +#ifdef __linux__ + /* Try proc for backward Linux compatibility */ + if (!access("/proc/dri/0", R_OK)) return 1; +#endif + return 0; + } + + if ((version = drmGetVersion(fd))) { + retval = 1; + drmFreeVersion(version); + } + close(fd); + + return retval; +} + + +/** + * Open the device by bus ID. + * + * \param busid bus ID. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * This function attempts to open every possible minor (up to DRM_MAX_MINOR), + * comparing the device bus ID with the one supplied. + * + * \sa drmOpenMinor() and drmGetBusid(). + */ +static int drmOpenByBusid(const char *busid) +{ + int i; + int fd; + const char *buf; + drmSetVersion sv; + + drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); + for (i = 0; i < DRM_MAX_MINOR; i++) { + fd = drmOpenMinor(i, 1); + drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); + if (fd >= 0) { + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; /* Don't care */ + drmSetInterfaceVersion(fd, &sv); + buf = drmGetBusid(fd); + drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); + if (buf && drmMatchBusID(buf, busid)) { + drmFreeBusid(buf); + return fd; + } + if (buf) drmFreeBusid(buf); + close(fd); + } + } + return -1; +} + + +/** + * Open the device by name. + * + * \param name driver name. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * This function opens the first minor number that matches the driver name and + * isn't already in use. If it's in use it then it will already have a bus ID + * assigned. + * + * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). + */ +static int drmOpenByName(const char *name) +{ + int i; + int fd; + drmVersionPtr version; + char * id; + + if (!drmAvailable()) { +#if !defined(XFree86Server) + return -1; +#else + /* try to load the kernel module now */ + if (!xf86LoadKernelModule(name)) { + ErrorF("[drm] failed to load kernel module \"%s\"\n", + name); + return -1; + } +#endif + } + + /* + * Open the first minor number that matches the driver name and isn't + * already in use. If it's in use it will have a busid assigned already. + */ + for (i = 0; i < DRM_MAX_MINOR; i++) { + if ((fd = drmOpenMinor(i, 1)) >= 0) { + if ((version = drmGetVersion(fd))) { + if (!strcmp(version->name, name)) { + drmFreeVersion(version); + id = drmGetBusid(fd); + drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); + if (!id || !*id) { + if (id) { + drmFreeBusid(id); + } + return fd; + } else { + drmFreeBusid(id); + } + } else { + drmFreeVersion(version); + } + } + close(fd); + } + } + +#ifdef __linux__ + /* Backward-compatibility /proc support */ + for (i = 0; i < 8; i++) { + char proc_name[64], buf[512]; + char *driver, *pt, *devstring; + int retcode; + + sprintf(proc_name, "/proc/dri/%d/name", i); + if ((fd = open(proc_name, 0, 0)) >= 0) { + retcode = read(fd, buf, sizeof(buf)-1); + close(fd); + if (retcode) { + buf[retcode-1] = '\0'; + for (driver = pt = buf; *pt && *pt != ' '; ++pt) + ; + if (*pt) { /* Device is next */ + *pt = '\0'; + if (!strcmp(driver, name)) { /* Match */ + for (devstring = ++pt; *pt && *pt != ' '; ++pt) + ; + if (*pt) { /* Found busid */ + return drmOpenByBusid(++pt); + } else { /* No busid */ + return drmOpenDevice(strtol(devstring, NULL, 0),i); + } + } + } + } + } + } +#endif + + return -1; +} + + +/** + * Open the DRM device. + * + * Looks up the specified name and bus ID, and opens the device found. The + * entry in /dev/dri is created if necessary and if called by root. + * + * \param name driver name. Not referenced if bus ID is supplied. + * \param busid bus ID. Zero if not known. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() + * otherwise. + */ +int drmOpen(const char *name, const char *busid) +{ +#ifdef XFree86Server + if (!drmAvailable() && name != NULL) { + /* try to load the kernel */ + if (!xf86LoadKernelModule(name)) { + ErrorF("[drm] failed to load kernel module \"%s\"\n", + name); + return -1; + } + } +#endif + + if (busid) { + int fd; + + fd = drmOpenByBusid(busid); + if (fd >= 0) + return fd; + } + if (name) + return drmOpenByName(name); + return -1; +} + + +/** + * Free the version information returned by drmGetVersion(). + * + * \param v pointer to the version information. + * + * \internal + * It frees the memory pointed by \p %v as well as all the non-null strings + * pointers in it. + */ +void drmFreeVersion(drmVersionPtr v) +{ + if (!v) return; + if (v->name) drmFree(v->name); + if (v->date) drmFree(v->date); + if (v->desc) drmFree(v->desc); + drmFree(v); +} + + +/** + * Free the non-public version information returned by the kernel. + * + * \param v pointer to the version information. + * + * \internal + * Used by drmGetVersion() to free the memory pointed by \p %v as well as all + * the non-null strings pointers in it. + */ +static void drmFreeKernelVersion(drm_version_t *v) +{ + if (!v) return; + if (v->name) drmFree(v->name); + if (v->date) drmFree(v->date); + if (v->desc) drmFree(v->desc); + drmFree(v); +} + + +/** + * Copy version information. + * + * \param d destination pointer. + * \param s source pointer. + * + * \internal + * Used by drmGetVersion() to translate the information returned by the ioctl + * interface in a private structure into the public structure counterpart. + */ +static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) +{ + d->version_major = s->version_major; + d->version_minor = s->version_minor; + d->version_patchlevel = s->version_patchlevel; + d->name_len = s->name_len; + d->name = drmStrdup(s->name); + d->date_len = s->date_len; + d->date = drmStrdup(s->date); + d->desc_len = s->desc_len; + d->desc = drmStrdup(s->desc); +} + + +/** + * Query the driver version information. + * + * \param fd file descriptor. + * + * \return pointer to a drmVersion structure which should be freed with + * drmFreeVersion(). + * + * \note Similar information is available via /proc/dri. + * + * \internal + * It gets the version information via successive DRM_IOCTL_VERSION ioctls, + * first with zeros to get the string lengths, and then the actually strings. + * It also null-terminates them since they might not be already. + */ +drmVersionPtr drmGetVersion(int fd) +{ + drmVersionPtr retval; + drm_version_t *version = drmMalloc(sizeof(*version)); + + /* First, get the lengths */ + version->name_len = 0; + version->name = NULL; + version->date_len = 0; + version->date = NULL; + version->desc_len = 0; + version->desc = NULL; + + if (ioctl(fd, DRM_IOCTL_VERSION, version)) { + drmFreeKernelVersion(version); + return NULL; + } + + /* Now, allocate space and get the data */ + if (version->name_len) + version->name = drmMalloc(version->name_len + 1); + if (version->date_len) + version->date = drmMalloc(version->date_len + 1); + if (version->desc_len) + version->desc = drmMalloc(version->desc_len + 1); + + if (ioctl(fd, DRM_IOCTL_VERSION, version)) { + drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); + drmFreeKernelVersion(version); + return NULL; + } + + /* The results might not be null-terminated + strings, so terminate them. */ + + if (version->name_len) version->name[version->name_len] = '\0'; + if (version->date_len) version->date[version->date_len] = '\0'; + if (version->desc_len) version->desc[version->desc_len] = '\0'; + + /* Now, copy it all back into the + client-visible data structure... */ + retval = drmMalloc(sizeof(*retval)); + drmCopyVersion(retval, version); + drmFreeKernelVersion(version); + return retval; +} + + +/** + * Get version information for the DRM user space library. + * + * This version number is driver independent. + * + * \param fd file descriptor. + * + * \return version information. + * + * \internal + * This function allocates and fills a drm_version structure with a hard coded + * version number. + */ +drmVersionPtr drmGetLibVersion(int fd) +{ + drm_version_t *version = drmMalloc(sizeof(*version)); + + /* Version history: + * revision 1.0.x = original DRM interface with no drmGetLibVersion + * entry point and many drm extensions + * revision 1.1.x = added drmCommand entry points for device extensions + * added drmGetLibVersion to identify libdrm.a version + * revision 1.2.x = added drmSetInterfaceVersion + * modified drmOpen to handle both busid and name + */ + version->version_major = 1; + version->version_minor = 2; + version->version_patchlevel = 0; + + return (drmVersionPtr)version; +} + + +/** + * Free the bus ID information. + * + * \param busid bus ID information string as given by drmGetBusid(). + * + * \internal + * This function is just frees the memory pointed by \p busid. + */ +void drmFreeBusid(const char *busid) +{ + drmFree((void *)busid); +} + + +/** + * Get the bus ID of the device. + * + * \param fd file descriptor. + * + * \return bus ID string. + * + * \internal + * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to + * get the string length and data, passing the arguments in a drm_unique + * structure. + */ +char *drmGetBusid(int fd) +{ + drm_unique_t u; + + u.unique_len = 0; + u.unique = NULL; + + if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL; + u.unique = drmMalloc(u.unique_len + 1); + if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL; + u.unique[u.unique_len] = '\0'; + + return u.unique; +} + + +/** + * Set the bus ID of the device. + * + * \param fd file descriptor. + * \param busid bus ID string. + * + * \return zero on success, negative on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing + * the arguments in a drm_unique structure. + */ +int drmSetBusid(int fd, const char *busid) +{ + drm_unique_t u; + + u.unique = (char *)busid; + u.unique_len = strlen(busid); + + if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { + return -errno; + } + return 0; +} + +int drmGetMagic(int fd, drmMagicPtr magic) +{ + drm_auth_t auth; + + *magic = 0; + if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) return -errno; + *magic = auth.magic; + return 0; +} + +int drmAuthMagic(int fd, drmMagic magic) +{ + drm_auth_t auth; + + auth.magic = magic; + if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) return -errno; + return 0; +} + +/** + * Specifies a range of memory that is available for mapping by a + * non-root process. + * + * \param fd file descriptor. + * \param offset usually the physical address. The actual meaning depends of + * the \p type parameter. See below. + * \param size of the memory in bytes. + * \param type type of the memory to be mapped. + * \param flags combination of several flags to modify the function actions. + * \param handle will be set to a value that may be used as the offset + * parameter for mmap(). + * + * \return zero on success or a negative value on error. + * + * \par Mapping the frame buffer + * For the frame buffer + * - \p offset will be the physical address of the start of the frame buffer, + * - \p size will be the size of the frame buffer in bytes, and + * - \p type will be DRM_FRAME_BUFFER. + * + * \par + * The area mapped will be uncached. If MTRR support is available in the + * kernel, the frame buffer area will be set to write combining. + * + * \par Mapping the MMIO register area + * For the MMIO register area, + * - \p offset will be the physical address of the start of the register area, + * - \p size will be the size of the register area bytes, and + * - \p type will be DRM_REGISTERS. + * \par + * The area mapped will be uncached. + * + * \par Mapping the SAREA + * For the SAREA, + * - \p offset will be ignored and should be set to zero, + * - \p size will be the desired size of the SAREA in bytes, + * - \p type will be DRM_SHM. + * + * \par + * A shared memory area of the requested size will be created and locked in + * kernel memory. This area may be mapped into client-space by using the handle + * returned. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing + * the arguments in a drm_map structure. + */ +int drmAddMap(int fd, + drmHandle offset, + drmSize size, + drmMapType type, + drmMapFlags flags, + drmHandlePtr handle) +{ + drm_map_t map; + + map.offset = offset; +/* No longer needed with CVS kernel modules on alpha +#ifdef __alpha__ + if (type != DRM_SHM) + map.offset += BUS_BASE; +#endif +*/ + map.size = size; + map.handle = 0; + map.type = type; + map.flags = flags; + if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno; + if (handle) *handle = (drmHandle)map.handle; + return 0; +} + +int drmRmMap(int fd, drmHandle handle) +{ + drm_map_t map; + + map.handle = (void *)handle; + + if(ioctl(fd, DRM_IOCTL_RM_MAP, &map)) return -errno; + return 0; +} + +/** + * Make buffers available for DMA transfers. + * + * \param fd file descriptor. + * \param count number of buffers. + * \param size size of each buffer. + * \param flags buffer allocation flags. + * \param agp_offset offset in the AGP aperture + * + * \return number of buffers allocated, negative on error. + * + * \internal + * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. + * + * \sa drm_buf_desc. + */ +int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, + int agp_offset) +{ + drm_buf_desc_t request; + + request.count = count; + request.size = size; + request.low_mark = 0; + request.high_mark = 0; + request.flags = flags; + request.agp_start = agp_offset; + + if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno; + return request.count; +} + +int drmMarkBufs(int fd, double low, double high) +{ + drm_buf_info_t info; + int i; + + info.count = 0; + info.list = NULL; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL; + + if (!info.count) return -EINVAL; + + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) + return -ENOMEM; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { + int retval = -errno; + drmFree(info.list); + return retval; + } + + for (i = 0; i < info.count; i++) { + info.list[i].low_mark = low * info.list[i].count; + info.list[i].high_mark = high * info.list[i].count; + if (ioctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { + int retval = -errno; + drmFree(info.list); + return retval; + } + } + drmFree(info.list); + + return 0; +} + +/** + * Free buffers. + * + * \param fd file descriptor. + * \param count number of buffers to free. + * \param list list of buffers to be freed. + * + * \return zero on success, or a negative value on failure. + * + * \note This function is primarily used for debugging. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing + * the arguments in a drm_buf_free structure. + */ +int drmFreeBufs(int fd, int count, int *list) +{ + drm_buf_free_t request; + + request.count = count; + request.list = list; + if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno; + return 0; +} + + +/** + * Close the device. + * + * \param fd file descriptor. + * + * \internal + * This function closes the file descriptor. + */ +int drmClose(int fd) +{ + unsigned long key = drmGetKeyFromFd(fd); + drmHashEntry *entry = drmGetEntry(fd); + + drmHashDestroy(entry->tagTable); + entry->fd = 0; + entry->f = NULL; + entry->tagTable = NULL; + + drmHashDelete(drmHashTable, key); + drmFree(entry); + + return close(fd); +} + + +/** + * Map a region of memory. + * + * \param fd file descriptor. + * \param handle handle returned by drmAddMap(). + * \param size size in bytes. Must match the size used by drmAddMap(). + * \param address will contain the user-space virtual address where the mapping + * begins. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper for mmap(). + */ +int drmMap(int fd, + drmHandle handle, + drmSize size, + drmAddressPtr address) +{ + static unsigned long pagesize_mask = 0; + + if (fd < 0) return -EINVAL; + + if (!pagesize_mask) + pagesize_mask = getpagesize() - 1; + + size = (size + pagesize_mask) & ~pagesize_mask; + + *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); + if (*address == MAP_FAILED) return -errno; + return 0; +} + + +/** + * Unmap mappings obtained with drmMap(). + * + * \param address address as given by drmMap(). + * \param size size in bytes. Must match the size used by drmMap(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper for unmap(). + */ +int drmUnmap(drmAddress address, drmSize size) +{ + return munmap(address, size); +} + +drmBufInfoPtr drmGetBufInfo(int fd) +{ + drm_buf_info_t info; + drmBufInfoPtr retval; + int i; + + info.count = 0; + info.list = NULL; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return NULL; + + if (info.count) { + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) + return NULL; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { + drmFree(info.list); + return NULL; + } + /* Now, copy it all back into the + client-visible data structure... */ + retval = drmMalloc(sizeof(*retval)); + retval->count = info.count; + retval->list = drmMalloc(info.count * sizeof(*retval->list)); + for (i = 0; i < info.count; i++) { + retval->list[i].count = info.list[i].count; + retval->list[i].size = info.list[i].size; + retval->list[i].low_mark = info.list[i].low_mark; + retval->list[i].high_mark = info.list[i].high_mark; + } + drmFree(info.list); + return retval; + } + return NULL; +} + +/** + * Map all DMA buffers into client-virtual space. + * + * \param fd file descriptor. + * + * \return a pointer to a ::drmBufMap structure. + * + * \note The client may not use these buffers until obtaining buffer indices + * with drmDMA(). + * + * \internal + * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned + * information about the buffers in a drm_buf_map structure into the + * client-visible data structures. + */ +drmBufMapPtr drmMapBufs(int fd) +{ + drm_buf_map_t bufs; + drmBufMapPtr retval; + int i; + + bufs.count = 0; + bufs.list = NULL; + if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL; + + if (bufs.count) { + if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) + return NULL; + + if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { + drmFree(bufs.list); + return NULL; + } + /* Now, copy it all back into the + client-visible data structure... */ + retval = drmMalloc(sizeof(*retval)); + retval->count = bufs.count; + retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); + for (i = 0; i < bufs.count; i++) { + retval->list[i].idx = bufs.list[i].idx; + retval->list[i].total = bufs.list[i].total; + retval->list[i].used = 0; + retval->list[i].address = bufs.list[i].address; + } + return retval; + } + return NULL; +} + + +/** + * Unmap buffers allocated with drmMapBufs(). + * + * \return zero on success, or negative value on failure. + * + * \internal + * Calls munmap() for every buffer stored in \p bufs. + */ +int drmUnmapBufs(drmBufMapPtr bufs) +{ + int i; + + for (i = 0; i < bufs->count; i++) { + munmap(bufs->list[i].address, bufs->list[i].total); + } + return 0; +} + + +#define DRM_DMA_RETRY 16 + +/** + * Reserve DMA buffers. + * + * \param fd file descriptor. + * \param request + * + * \return zero on success, or a negative value on failure. + * + * \internal + * Assemble the arguments into a drm_dma structure and keeps issuing the + * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. + */ +int drmDMA(int fd, drmDMAReqPtr request) +{ + drm_dma_t dma; + int ret, i = 0; + + /* Copy to hidden structure */ + dma.context = request->context; + dma.send_count = request->send_count; + dma.send_indices = request->send_list; + dma.send_sizes = request->send_sizes; + dma.flags = request->flags; + dma.request_count = request->request_count; + dma.request_size = request->request_size; + dma.request_indices = request->request_list; + dma.request_sizes = request->request_sizes; + + do { + ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); + } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); + + if ( ret == 0 ) { + request->granted_count = dma.granted_count; + return 0; + } else { + return -errno; + } +} + + +/** + * Obtain heavyweight hardware lock. + * + * \param fd file descriptor. + * \param context context. + * \param flags flags that determine the sate of the hardware when the function + * returns. + * + * \return always zero. + * + * \internal + * This function translates the arguments into a drm_lock structure and issue + * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. + */ +int drmGetLock(int fd, drmContext context, drmLockFlags flags) +{ + drm_lock_t lock; + + lock.context = context; + lock.flags = 0; + if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; + if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; + if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; + if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; + if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; + if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; + + while (ioctl(fd, DRM_IOCTL_LOCK, &lock)) + ; + return 0; +} + +/** + * Release the hardware lock. + * + * \param fd file descriptor. + * \param context context. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the + * argument in a drm_lock structure. + */ +int drmUnlock(int fd, drmContext context) +{ + drm_lock_t lock; + + lock.context = context; + lock.flags = 0; + return ioctl(fd, DRM_IOCTL_UNLOCK, &lock); +} + +drmContextPtr drmGetReservedContextList(int fd, int *count) +{ + drm_ctx_res_t res; + drm_ctx_t *list; + drmContextPtr retval; + int i; + + res.count = 0; + res.contexts = NULL; + if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL; + + if (!res.count) return NULL; + + if (!(list = drmMalloc(res.count * sizeof(*list)))) return NULL; + if (!(retval = drmMalloc(res.count * sizeof(*retval)))) { + drmFree(list); + return NULL; + } + + res.contexts = list; + if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL; + + for (i = 0; i < res.count; i++) retval[i] = list[i].handle; + drmFree(list); + + *count = res.count; + return retval; +} + +void drmFreeReservedContextList(drmContextPtr pt) +{ + drmFree(pt); +} + +/** + * Create context. + * + * Used by the X server during GLXContext initialization. This causes + * per-context kernel-level resources to be allocated. + * + * \param fd file descriptor. + * \param handle is set on success. To be used by the client when requesting DMA + * dispatch with drmDMA(). + * + * \return zero on success, or a negative value on failure. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the + * argument in a drm_ctx structure. + */ +int drmCreateContext(int fd, drmContextPtr handle) +{ + drm_ctx_t ctx; + + ctx.flags = 0; /* Modified with functions below */ + if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno; + *handle = ctx.handle; + return 0; +} + +int drmSwitchToContext(int fd, drmContext context) +{ + drm_ctx_t ctx; + + ctx.handle = context; + if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) return -errno; + return 0; +} + +int drmSetContextFlags(int fd, drmContext context, drmContextFlags flags) +{ + drm_ctx_t ctx; + + /* Context preserving means that no context + switched are done between DMA buffers + from one context and the next. This is + suitable for use in the X server (which + promises to maintain hardware context, + or in the client-side library when + buffers are swapped on behalf of two + threads. */ + ctx.handle = context; + ctx.flags = 0; + if (flags & DRM_CONTEXT_PRESERVED) ctx.flags |= _DRM_CONTEXT_PRESERVED; + if (flags & DRM_CONTEXT_2DONLY) ctx.flags |= _DRM_CONTEXT_2DONLY; + if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) return -errno; + return 0; +} + +int drmGetContextFlags(int fd, drmContext context, drmContextFlagsPtr flags) +{ + drm_ctx_t ctx; + + ctx.handle = context; + if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx)) return -errno; + *flags = 0; + if (ctx.flags & _DRM_CONTEXT_PRESERVED) *flags |= DRM_CONTEXT_PRESERVED; + if (ctx.flags & _DRM_CONTEXT_2DONLY) *flags |= DRM_CONTEXT_2DONLY; + return 0; +} + +/** + * Destroy context. + * + * Free any kernel-level resources allocated with drmCreateContext() associated + * with the context. + * + * \param fd file descriptor. + * \param handle handle given by drmCreateContext(). + * + * \return zero on success, or a negative value on failure. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the + * argument in a drm_ctx structure. + */ +int drmDestroyContext(int fd, drmContext handle) +{ + drm_ctx_t ctx; + ctx.handle = handle; + if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno; + return 0; +} + +int drmCreateDrawable(int fd, drmDrawablePtr handle) +{ + drm_draw_t draw; + if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) return -errno; + *handle = draw.handle; + return 0; +} + +int drmDestroyDrawable(int fd, drmDrawable handle) +{ + drm_draw_t draw; + draw.handle = handle; + if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw)) return -errno; + return 0; +} + +/** + * Acquire the AGP device. + * + * Must be called before any of the other AGP related calls. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. + */ +int drmAgpAcquire(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno; + return 0; +} + + +/** + * Release the AGP device. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. + */ +int drmAgpRelease(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno; + return 0; +} + + +/** + * Set the AGP mode. + * + * \param fd file descriptor. + * \param mode AGP mode. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the + * argument in a drm_agp_mode structure. + */ +int drmAgpEnable(int fd, unsigned long mode) +{ + drm_agp_mode_t m; + + m.mode = mode; + if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno; + return 0; +} + + +/** + * Allocate a chunk of AGP memory. + * + * \param fd file descriptor. + * \param size requested memory size in bytes. Will be rounded to page boundary. + * \param type type of memory to allocate. + * \param address if not zero, will be set to the physical address of the + * allocated memory. + * \param handle on success will be set to a handle of the allocated memory. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the + * arguments in a drm_agp_buffer structure. + */ +int drmAgpAlloc(int fd, unsigned long size, unsigned long type, + unsigned long *address, unsigned long *handle) +{ + drm_agp_buffer_t b; + + *handle = DRM_AGP_NO_HANDLE; + b.size = size; + b.handle = 0; + b.type = type; + if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno; + if (address != 0UL) *address = b.physical; + *handle = b.handle; + return 0; +} + + +/** + * Free a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the + * argument in a drm_agp_buffer structure. + */ +int drmAgpFree(int fd, unsigned long handle) +{ + drm_agp_buffer_t b; + + b.size = 0; + b.handle = handle; + if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno; + return 0; +} + + +/** + * Bind a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * \param offset offset in bytes. It will round to page boundary. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the + * argument in a drm_agp_binding structure. + */ +int drmAgpBind(int fd, unsigned long handle, unsigned long offset) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = offset; + if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno; + return 0; +} + + +/** + * Unbind a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing + * the argument in a drm_agp_binding structure. + */ +int drmAgpUnbind(int fd, unsigned long handle) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = 0; + if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno; + return 0; +} + + +/** + * Get AGP driver major version number. + * + * \param fd file descriptor. + * + * \return major version number on success, or a negative value on failure.. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +int drmAgpVersionMajor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_major; +} + + +/** + * Get AGP driver minor version number. + * + * \param fd file descriptor. + * + * \return minor version number on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +int drmAgpVersionMinor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_minor; +} + + +/** + * Get AGP mode. + * + * \param fd file descriptor. + * + * \return mode on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpGetMode(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.mode; +} + + +/** + * Get AGP aperture base. + * + * \param fd file descriptor. + * + * \return aperture base on success, zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpBase(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_base; +} + + +/** + * Get AGP aperture size. + * + * \param fd file descriptor. + * + * \return aperture size on success, zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpSize(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_size; +} + + +/** + * Get used AGP memory. + * + * \param fd file descriptor. + * + * \return memory used on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpMemoryUsed(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_used; +} + + +/** + * Get available AGP memory. + * + * \param fd file descriptor. + * + * \return memory available on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpMemoryAvail(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_allowed; +} + + +/** + * Get hardware vendor ID. + * + * \param fd file descriptor. + * + * \return vendor ID on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned int drmAgpVendorId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_vendor; +} + + +/** + * Get hardware device ID. + * + * \param fd file descriptor. + * + * \return zero on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned int drmAgpDeviceId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_device; +} + +int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle) +{ + drm_scatter_gather_t sg; + + *handle = 0; + sg.size = size; + sg.handle = 0; + if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno; + *handle = sg.handle; + return 0; +} + +int drmScatterGatherFree(int fd, unsigned long handle) +{ + drm_scatter_gather_t sg; + + sg.size = 0; + sg.handle = handle; + if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno; + return 0; +} + +/** + * Wait for VBLANK. + * + * \param fd file descriptor. + * \param vbl pointer to a drmVBlank structure. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. + */ +int drmWaitVBlank(int fd, drmVBlankPtr vbl) +{ + int ret; + + do { + ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); + vbl->request.type &= ~DRM_VBLANK_RELATIVE; + } while (ret && errno == EINTR); + + return ret; +} + +int drmError(int err, const char *label) +{ + switch (err) { + case DRM_ERR_NO_DEVICE: fprintf(stderr, "%s: no device\n", label); break; + case DRM_ERR_NO_ACCESS: fprintf(stderr, "%s: no access\n", label); break; + case DRM_ERR_NOT_ROOT: fprintf(stderr, "%s: not root\n", label); break; + case DRM_ERR_INVALID: fprintf(stderr, "%s: invalid args\n", label);break; + default: + if (err < 0) err = -err; + fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); + break; + } + + return 1; +} + +/** + * Install IRQ handler. + * + * \param fd file descriptor. + * \param irq IRQ number. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the + * argument in a drm_control structure. + */ +int drmCtlInstHandler(int fd, int irq) +{ + drm_control_t ctl; + + ctl.func = DRM_INST_HANDLER; + ctl.irq = irq; + if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno; + return 0; +} + + +/** + * Uninstall IRQ handler. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the + * argument in a drm_control structure. + */ +int drmCtlUninstHandler(int fd) +{ + drm_control_t ctl; + + ctl.func = DRM_UNINST_HANDLER; + ctl.irq = 0; + if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno; + return 0; +} + +int drmFinish(int fd, int context, drmLockFlags flags) +{ + drm_lock_t lock; + + lock.context = context; + lock.flags = 0; + if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; + if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; + if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; + if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; + if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; + if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; + if (ioctl(fd, DRM_IOCTL_FINISH, &lock)) return -errno; + return 0; +} + +/** + * Get IRQ from bus ID. + * + * \param fd file descriptor. + * \param busnum bus number. + * \param devnum device number. + * \param funcnum function number. + * + * \return IRQ number on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the + * arguments in a drm_irq_busid structure. + */ +int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum) +{ + drm_irq_busid_t p; + + p.busnum = busnum; + p.devnum = devnum; + p.funcnum = funcnum; + if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno; + return p.irq; +} + +int drmAddContextTag(int fd, drmContext context, void *tag) +{ + drmHashEntry *entry = drmGetEntry(fd); + + if (drmHashInsert(entry->tagTable, context, tag)) { + drmHashDelete(entry->tagTable, context); + drmHashInsert(entry->tagTable, context, tag); + } + return 0; +} + +int drmDelContextTag(int fd, drmContext context) +{ + drmHashEntry *entry = drmGetEntry(fd); + + return drmHashDelete(entry->tagTable, context); +} + +void *drmGetContextTag(int fd, drmContext context) +{ + drmHashEntry *entry = drmGetEntry(fd); + void *value; + + if (drmHashLookup(entry->tagTable, context, &value)) return NULL; + + return value; +} + +int drmAddContextPrivateMapping(int fd, drmContext ctx_id, drmHandle handle) +{ + drm_ctx_priv_map_t map; + + map.ctx_id = ctx_id; + map.handle = (void *)handle; + + if (ioctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) return -errno; + return 0; +} + +int drmGetContextPrivateMapping(int fd, drmContext ctx_id, drmHandlePtr handle) +{ + drm_ctx_priv_map_t map; + + map.ctx_id = ctx_id; + + if (ioctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) return -errno; + if (handle) *handle = (drmHandle)map.handle; + + return 0; +} + +int drmGetMap(int fd, int idx, drmHandle *offset, drmSize *size, + drmMapType *type, drmMapFlags *flags, drmHandle *handle, + int *mtrr) +{ + drm_map_t map; + + map.offset = idx; + if (ioctl(fd, DRM_IOCTL_GET_MAP, &map)) return -errno; + *offset = map.offset; + *size = map.size; + *type = map.type; + *flags = map.flags; + *handle = (unsigned long)map.handle; + *mtrr = map.mtrr; + return 0; +} + +int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, + unsigned long *magic, unsigned long *iocs) +{ + drm_client_t client; + + client.idx = idx; + if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client)) return -errno; + *auth = client.auth; + *pid = client.pid; + *uid = client.uid; + *magic = client.magic; + *iocs = client.iocs; + return 0; +} + +int drmGetStats(int fd, drmStatsT *stats) +{ + drm_stats_t s; + int i; + + if (ioctl(fd, DRM_IOCTL_GET_STATS, &s)) return -errno; + + stats->count = 0; + memset(stats, 0, sizeof(*stats)); + if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) + return -1; + +#define SET_VALUE \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%8.8s"; \ + stats->data[i].isvalue = 1; \ + stats->data[i].verbose = 0 + +#define SET_COUNT \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%5.5s"; \ + stats->data[i].isvalue = 0; \ + stats->data[i].mult_names = "kgm"; \ + stats->data[i].mult = 1000; \ + stats->data[i].verbose = 0 + +#define SET_BYTE \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%5.5s"; \ + stats->data[i].isvalue = 0; \ + stats->data[i].mult_names = "KGM"; \ + stats->data[i].mult = 1024; \ + stats->data[i].verbose = 0 + + + stats->count = s.count; + for (i = 0; i < s.count; i++) { + stats->data[i].value = s.data[i].value; + switch (s.data[i].type) { + case _DRM_STAT_LOCK: + stats->data[i].long_name = "Lock"; + stats->data[i].rate_name = "Lock"; + SET_VALUE; + break; + case _DRM_STAT_OPENS: + stats->data[i].long_name = "Opens"; + stats->data[i].rate_name = "O"; + SET_COUNT; + stats->data[i].verbose = 1; + break; + case _DRM_STAT_CLOSES: + stats->data[i].long_name = "Closes"; + stats->data[i].rate_name = "Lock"; + SET_COUNT; + stats->data[i].verbose = 1; + break; + case _DRM_STAT_IOCTLS: + stats->data[i].long_name = "Ioctls"; + stats->data[i].rate_name = "Ioc/s"; + SET_COUNT; + break; + case _DRM_STAT_LOCKS: + stats->data[i].long_name = "Locks"; + stats->data[i].rate_name = "Lck/s"; + SET_COUNT; + break; + case _DRM_STAT_UNLOCKS: + stats->data[i].long_name = "Unlocks"; + stats->data[i].rate_name = "Unl/s"; + SET_COUNT; + break; + case _DRM_STAT_IRQ: + stats->data[i].long_name = "IRQs"; + stats->data[i].rate_name = "IRQ/s"; + SET_COUNT; + break; + case _DRM_STAT_PRIMARY: + stats->data[i].long_name = "Primary Bytes"; + stats->data[i].rate_name = "PB/s"; + SET_BYTE; + break; + case _DRM_STAT_SECONDARY: + stats->data[i].long_name = "Secondary Bytes"; + stats->data[i].rate_name = "SB/s"; + SET_BYTE; + break; + case _DRM_STAT_DMA: + stats->data[i].long_name = "DMA"; + stats->data[i].rate_name = "DMA/s"; + SET_COUNT; + break; + case _DRM_STAT_SPECIAL: + stats->data[i].long_name = "Special DMA"; + stats->data[i].rate_name = "dma/s"; + SET_COUNT; + break; + case _DRM_STAT_MISSED: + stats->data[i].long_name = "Miss"; + stats->data[i].rate_name = "Ms/s"; + SET_COUNT; + break; + case _DRM_STAT_VALUE: + stats->data[i].long_name = "Value"; + stats->data[i].rate_name = "Value"; + SET_VALUE; + break; + case _DRM_STAT_BYTE: + stats->data[i].long_name = "Bytes"; + stats->data[i].rate_name = "B/s"; + SET_BYTE; + break; + case _DRM_STAT_COUNT: + default: + stats->data[i].long_name = "Count"; + stats->data[i].rate_name = "Cnt/s"; + SET_COUNT; + break; + } + } + return 0; +} + +/** + * Issue a set-version ioctl. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be read and written. + * \param size size of the data to be read and written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read-write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmSetInterfaceVersion(int fd, drmSetVersion *version ) +{ + int retcode = 0; + drm_set_version_t sv; + + sv.drm_di_major = version->drm_di_major; + sv.drm_di_minor = version->drm_di_minor; + sv.drm_dd_major = version->drm_dd_major; + sv.drm_dd_minor = version->drm_dd_minor; + + if (ioctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { + retcode = -errno; + } + + version->drm_di_major = sv.drm_di_major; + version->drm_di_minor = sv.drm_di_minor; + version->drm_dd_major = sv.drm_dd_major; + version->drm_dd_minor = sv.drm_dd_minor; + + return retcode; +} + +/** + * Send a device-specific command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandNone(int fd, unsigned long drmCommandIndex) +{ + void *data = NULL; /* dummy */ + unsigned long request; + + request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific read command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data destination pointer of the data to be read. + * \param size size of the data to be read. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size ) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific write command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be written. + * \param size size of the data to be written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size ) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific read-write command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be read and written. + * \param size size of the data to be read and written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read-write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size ) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + +#if defined(XFree86Server) || defined(DRM_USE_MALLOC) +static void drmSIGIOHandler(int interrupt, void *closure) +{ + unsigned long key; + void *value; + ssize_t count; + drm_ctx_t ctx; + typedef void (*_drmCallback)(int, void *, void *); + char buf[256]; + drmContext old; + drmContext new; + void *oldctx; + void *newctx; + char *pt; + drmHashEntry *entry; + + if (!drmHashTable) return; + if (drmHashFirst(drmHashTable, &key, &value)) { + entry = value; + do { +#if 0 + fprintf(stderr, "Trying %d\n", entry->fd); +#endif + if ((count = read(entry->fd, buf, sizeof(buf))) > 0) { + buf[count] = '\0'; +#if 0 + fprintf(stderr, "Got %s\n", buf); +#endif + + for (pt = buf; *pt != ' '; ++pt); /* Find first space */ + ++pt; + old = strtol(pt, &pt, 0); + new = strtol(pt, NULL, 0); + oldctx = drmGetContextTag(entry->fd, old); + newctx = drmGetContextTag(entry->fd, new); +#if 0 + fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx); +#endif + ((_drmCallback)entry->f)(entry->fd, oldctx, newctx); + ctx.handle = new; + ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx); + } + } while (drmHashNext(drmHashTable, &key, &value)); + } +} + +int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *)) +{ + drmHashEntry *entry; + + entry = drmGetEntry(fd); + entry->f = f; + + return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0); +} + +int drmRemoveSIGIOHandler(int fd) +{ + drmHashEntry *entry = drmGetEntry(fd); + + entry->f = NULL; + + return xf86RemoveSIGIOHandler(fd); +} +#endif diff --git a/src/mesa/drivers/dri/dri_client/xf86drmHash.c b/src/mesa/drivers/dri/dri_client/xf86drmHash.c new file mode 100644 index 00000000000..1f1a05b3ac9 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/xf86drmHash.c @@ -0,0 +1,435 @@ +/* xf86drmHash.c -- Small hash table support for integer -> integer mapping + * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith + * + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmHash.c,v 1.4 2001/03/21 18:08:54 dawes Exp $ + * + * DESCRIPTION + * + * This file contains a straightforward implementation of a fixed-sized + * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for + * collision resolution. There are two potentially interesting things + * about this implementation: + * + * 1) The table is power-of-two sized. Prime sized tables are more + * traditional, but do not have a significant advantage over power-of-two + * sized table, especially when double hashing is not used for collision + * resolution. + * + * 2) The hash computation uses a table of random integers [Hanson97, + * pp. 39-41]. + * + * FUTURE ENHANCEMENTS + * + * With a table size of 512, the current implementation is sufficient for a + * few hundred keys. Since this is well above the expected size of the + * tables for which this implementation was designed, the implementation of + * dynamic hash tables was postponed until the need arises. A common (and + * naive) approach to dynamic hash table implementation simply creates a + * new hash table when necessary, rehashes all the data into the new table, + * and destroys the old table. The approach in [Larson88] is superior in + * two ways: 1) only a portion of the table is expanded when needed, + * distributing the expansion cost over several insertions, and 2) portions + * of the table can be locked, enabling a scalable thread-safe + * implementation. + * + * REFERENCES + * + * [Hanson97] David R. Hanson. C Interfaces and Implementations: + * Techniques for Creating Reusable Software. Reading, Massachusetts: + * Addison-Wesley, 1997. + * + * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: + * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. + * + * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April + * 1988, pp. 446-457. + * + */ + +#define HASH_MAIN 0 + +#if HASH_MAIN +# include +# include +#else +# include "xf86drm.h" +# ifdef XFree86LOADER +# include "xf86.h" +# include "xf86_ansic.h" +# else +# include +# include +# endif +#endif + +#define N(x) drm##x + +#define HASH_MAGIC 0xdeadbeef +#define HASH_DEBUG 0 +#define HASH_SIZE 512 /* Good for about 100 entries */ + /* If you change this value, you probably + have to change the HashHash hashing + function! */ + +#if HASH_MAIN +#define HASH_ALLOC malloc +#define HASH_FREE free +#define HASH_RANDOM_DECL +#define HASH_RANDOM_INIT(seed) srandom(seed) +#define HASH_RANDOM random() +#else +#define HASH_ALLOC drmMalloc +#define HASH_FREE drmFree +#define HASH_RANDOM_DECL void *state +#define HASH_RANDOM_INIT(seed) state = drmRandomCreate(seed) +#define HASH_RANDOM drmRandom(state) + +#endif + +typedef struct HashBucket { + unsigned long key; + void *value; + struct HashBucket *next; +} HashBucket, *HashBucketPtr; + +typedef struct HashTable { + unsigned long magic; + unsigned long entries; + unsigned long hits; /* At top of linked list */ + unsigned long partials; /* Not at top of linked list */ + unsigned long misses; /* Not in table */ + HashBucketPtr buckets[HASH_SIZE]; + int p0; + HashBucketPtr p1; +} HashTable, *HashTablePtr; + +#if HASH_MAIN +extern void *N(HashCreate)(void); +extern int N(HashDestroy)(void *t); +extern int N(HashLookup)(void *t, unsigned long key, unsigned long *value); +extern int N(HashInsert)(void *t, unsigned long key, unsigned long value); +extern int N(HashDelete)(void *t, unsigned long key); +#endif + +static unsigned long HashHash(unsigned long key) +{ + unsigned long hash = 0; + unsigned long tmp = key; + static int init = 0; + static unsigned long scatter[256]; + int i; + + if (!init) { + HASH_RANDOM_DECL; + HASH_RANDOM_INIT(37); + for (i = 0; i < 256; i++) scatter[i] = HASH_RANDOM; + ++init; + } + + while (tmp) { + hash = (hash << 1) + scatter[tmp & 0xff]; + tmp >>= 8; + } + + hash %= HASH_SIZE; +#if HASH_DEBUG + printf( "Hash(%d) = %d\n", key, hash); +#endif + return hash; +} + +void *N(HashCreate)(void) +{ + HashTablePtr table; + int i; + + table = HASH_ALLOC(sizeof(*table)); + if (!table) return NULL; + table->magic = HASH_MAGIC; + table->entries = 0; + table->hits = 0; + table->partials = 0; + table->misses = 0; + + for (i = 0; i < HASH_SIZE; i++) table->buckets[i] = NULL; + return table; +} + +int N(HashDestroy)(void *t) +{ + HashTablePtr table = (HashTablePtr)t; + HashBucketPtr bucket; + HashBucketPtr next; + int i; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + for (i = 0; i < HASH_SIZE; i++) { + for (bucket = table->buckets[i]; bucket;) { + next = bucket->next; + HASH_FREE(bucket); + bucket = next; + } + } + HASH_FREE(table); + return 0; +} + +/* Find the bucket and organize the list so that this bucket is at the + top. */ + +static HashBucketPtr HashFind(HashTablePtr table, + unsigned long key, unsigned long *h) +{ + unsigned long hash = HashHash(key); + HashBucketPtr prev = NULL; + HashBucketPtr bucket; + + if (h) *h = hash; + + for (bucket = table->buckets[hash]; bucket; bucket = bucket->next) { + if (bucket->key == key) { + if (prev) { + /* Organize */ + prev->next = bucket->next; + bucket->next = table->buckets[hash]; + table->buckets[hash] = bucket; + ++table->partials; + } else { + ++table->hits; + } + return bucket; + } + prev = bucket; + } + ++table->misses; + return NULL; +} + +int N(HashLookup)(void *t, unsigned long key, void **value) +{ + HashTablePtr table = (HashTablePtr)t; + HashBucketPtr bucket; + + if (!table || table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + bucket = HashFind(table, key, NULL); + if (!bucket) return 1; /* Not found */ + *value = bucket->value; + return 0; /* Found */ +} + +int N(HashInsert)(void *t, unsigned long key, void *value) +{ + HashTablePtr table = (HashTablePtr)t; + HashBucketPtr bucket; + unsigned long hash; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + if (HashFind(table, key, &hash)) return 1; /* Already in table */ + + bucket = HASH_ALLOC(sizeof(*bucket)); + if (!bucket) return -1; /* Error */ + bucket->key = key; + bucket->value = value; + bucket->next = table->buckets[hash]; + table->buckets[hash] = bucket; +#if HASH_DEBUG + printf("Inserted %d at %d/%p\n", key, hash, bucket); +#endif + return 0; /* Added to table */ +} + +int N(HashDelete)(void *t, unsigned long key) +{ + HashTablePtr table = (HashTablePtr)t; + unsigned long hash; + HashBucketPtr bucket; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + bucket = HashFind(table, key, &hash); + + if (!bucket) return 1; /* Not found */ + + table->buckets[hash] = bucket->next; + HASH_FREE(bucket); + return 0; +} + +int N(HashNext)(void *t, unsigned long *key, void **value) +{ + HashTablePtr table = (HashTablePtr)t; + + for (; table->p0 < HASH_SIZE; + ++table->p0, table->p1 = table->buckets[table->p0]) { + if (table->p1) { + *key = table->p1->key; + *value = table->p1->value; + table->p1 = table->p1->next; + return 1; + } + } + return 0; +} + +int N(HashFirst)(void *t, unsigned long *key, void **value) +{ + HashTablePtr table = (HashTablePtr)t; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + table->p0 = 0; + table->p1 = table->buckets[0]; + return N(HashNext)(table, key, value); +} + +#if HASH_MAIN +#define DIST_LIMIT 10 +static int dist[DIST_LIMIT]; + +static void clear_dist(void) { + int i; + + for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; +} + +static int count_entries(HashBucketPtr bucket) +{ + int count = 0; + + for (; bucket; bucket = bucket->next) ++count; + return count; +} + +static void update_dist(int count) +{ + if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; + else ++dist[count]; +} + +static void compute_dist(HashTablePtr table) +{ + int i; + HashBucketPtr bucket; + + printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", + table->entries, table->hits, table->partials, table->misses); + clear_dist(); + for (i = 0; i < HASH_SIZE; i++) { + bucket = table->buckets[i]; + update_dist(count_entries(bucket)); + } + for (i = 0; i < DIST_LIMIT; i++) { + if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); + else printf("other %10d\n", dist[i]); + } +} + +static void check_table(HashTablePtr table, + unsigned long key, unsigned long value) +{ + unsigned long retval = 0; + int retcode = N(HashLookup)(table, key, &retval); + + switch (retcode) { + case -1: + printf("Bad magic = 0x%08lx:" + " key = %lu, expected = %lu, returned = %lu\n", + table->magic, key, value, retval); + break; + case 1: + printf("Not found: key = %lu, expected = %lu returned = %lu\n", + key, value, retval); + break; + case 0: + if (value != retval) + printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", + key, value, retval); + break; + default: + printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", + retcode, key, value, retval); + break; + } +} + +int main(void) +{ + HashTablePtr table; + int i; + + printf("\n***** 256 consecutive integers ****\n"); + table = N(HashCreate)(); + for (i = 0; i < 256; i++) N(HashInsert)(table, i, i); + for (i = 0; i < 256; i++) check_table(table, i, i); + for (i = 256; i >= 0; i--) check_table(table, i, i); + compute_dist(table); + N(HashDestroy)(table); + + printf("\n***** 1024 consecutive integers ****\n"); + table = N(HashCreate)(); + for (i = 0; i < 1024; i++) N(HashInsert)(table, i, i); + for (i = 0; i < 1024; i++) check_table(table, i, i); + for (i = 1024; i >= 0; i--) check_table(table, i, i); + compute_dist(table); + N(HashDestroy)(table); + + printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); + table = N(HashCreate)(); + for (i = 0; i < 1024; i++) N(HashInsert)(table, i*4096, i); + for (i = 0; i < 1024; i++) check_table(table, i*4096, i); + for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); + compute_dist(table); + N(HashDestroy)(table); + + printf("\n***** 1024 random integers ****\n"); + table = N(HashCreate)(); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) N(HashInsert)(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) check_table(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) check_table(table, random(), i); + compute_dist(table); + N(HashDestroy)(table); + + printf("\n***** 5000 random integers ****\n"); + table = N(HashCreate)(); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) N(HashInsert)(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) check_table(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) check_table(table, random(), i); + compute_dist(table); + N(HashDestroy)(table); + + return 0; +} +#endif diff --git a/src/mesa/drivers/dri/dri_client/xf86drmRandom.c b/src/mesa/drivers/dri/dri_client/xf86drmRandom.c new file mode 100644 index 00000000000..9e1e9ee2c34 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/xf86drmRandom.c @@ -0,0 +1,219 @@ +/* xf86drmRandom.c -- "Minimal Standard" PRNG Implementation + * Created: Mon Apr 19 08:28:13 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith + * + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmRandom.c,v 1.4 2000/06/17 00:03:34 martin Exp $ + * + * DESCRIPTION + * + * This file contains a simple, straightforward implementation of the Park + * & Miller "Minimal Standard" PRNG [PM88, PMS93], which is a Lehmer + * multiplicative linear congruential generator (MLCG) with a period of + * 2^31-1. + * + * This implementation is intended to provide a reliable, portable PRNG + * that is suitable for testing a hash table implementation and for + * implementing skip lists. + * + * FUTURE ENHANCEMENTS + * + * If initial seeds are not selected randomly, two instances of the PRNG + * can be correlated. [Knuth81, pp. 32-33] describes a shuffling technique + * that can eliminate this problem. + * + * If PRNGs are used for simulation, the period of the current + * implementation may be too short. [LE88] discusses methods of combining + * MLCGs to produce much longer periods, and suggests some alternative + * values for A and M. [LE90 and Sch92] also provide information on + * long-period PRNGs. + * + * REFERENCES + * + * [Knuth81] Donald E. Knuth. The Art of Computer Programming. Volume 2: + * Seminumerical Algorithms. Reading, Massachusetts: Addison-Wesley, 1981. + * + * [LE88] Pierre L'Ecuyer. "Efficient and Portable Combined Random Number + * Generators". CACM 31(6), June 1988, pp. 742-774. + * + * [LE90] Pierre L'Ecuyer. "Random Numbers for Simulation". CACM 33(10, + * October 1990, pp. 85-97. + * + * [PM88] Stephen K. Park and Keith W. Miller. "Random Number Generators: + * Good Ones are Hard to Find". CACM 31(10), October 1988, pp. 1192-1201. + * + * [Sch92] Bruce Schneier. "Pseudo-Ransom Sequence Generator for 32-Bit + * CPUs". Dr. Dobb's Journal 17(2), February 1992, pp. 34, 37-38, 40. + * + * [PMS93] Stephen K. Park, Keith W. Miller, and Paul K. Stockmeyer. In + * "Technical Correspondence: Remarks on Choosing and Implementing Random + * Number Generators". CACM 36(7), July 1993, pp. 105-110. + * + */ + +#define RANDOM_MAIN 0 + +#if RANDOM_MAIN +# include +# include +#else +# include "xf86drm.h" +# ifdef XFree86LOADER +# include "xf86.h" +# include "xf86_ansic.h" +# else +# include +# include +# endif +#endif + +#define N(x) drm##x + +#define RANDOM_MAGIC 0xfeedbeef +#define RANDOM_DEBUG 0 + +#if RANDOM_MAIN +#define RANDOM_ALLOC malloc +#define RANDOM_FREE free +#else +#define RANDOM_ALLOC drmMalloc +#define RANDOM_FREE drmFree +#endif + +typedef struct RandomState { + unsigned long magic; + unsigned long a; + unsigned long m; + unsigned long q; /* m div a */ + unsigned long r; /* m mod a */ + unsigned long check; + long seed; +} RandomState; + +#if RANDOM_MAIN +extern void *N(RandomCreate)(unsigned long seed); +extern int N(RandomDestroy)(void *state); +extern unsigned long N(Random)(void *state); +extern double N(RandomDouble)(void *state); +#endif + +void *N(RandomCreate)(unsigned long seed) +{ + RandomState *state; + + state = RANDOM_ALLOC(sizeof(*state)); + if (!state) return NULL; + state->magic = RANDOM_MAGIC; +#if 0 + /* Park & Miller, October 1988 */ + state->a = 16807; + state->m = 2147483647; + state->check = 1043618065; /* After 10000 iterations */ +#else + /* Park, Miller, and Stockmeyer, July 1993 */ + state->a = 48271; + state->m = 2147483647; + state->check = 399268537; /* After 10000 iterations */ +#endif + state->q = state->m / state->a; + state->r = state->m % state->a; + + state->seed = seed; + /* Check for illegal boundary conditions, + and choose closest legal value. */ + if (state->seed <= 0) state->seed = 1; + if (state->seed >= state->m) state->seed = state->m - 1; + + return state; +} + +int N(RandomDestroy)(void *state) +{ + RANDOM_FREE(state); + return 0; +} + +unsigned long N(Random)(void *state) +{ + RandomState *s = (RandomState *)state; + long hi; + long lo; + + hi = s->seed / s->q; + lo = s->seed % s->q; + s->seed = s->a * lo - s->r * hi; + if (s->seed <= 0) s->seed += s->m; + + return s->seed; +} + +double N(RandomDouble)(void *state) +{ + RandomState *s = (RandomState *)state; + + return (double)N(Random)(state)/(double)s->m; +} + +#if RANDOM_MAIN +static void check_period(long seed) +{ + unsigned long count = 0; + unsigned long initial; + void *state; + + state = N(RandomCreate)(seed); + initial = N(Random)(state); + ++count; + while (initial != N(Random)(state)) { + if (!++count) break; + } + printf("With seed of %10ld, period = %10lu (0x%08lx)\n", + seed, count, count); + N(RandomDestroy)(state); +} + +int main(void) +{ + RandomState *state; + int i; + unsigned long rand; + + state = N(RandomCreate)(1); + for (i = 0; i < 10000; i++) { + rand = N(Random)(state); + } + printf("After 10000 iterations: %lu (%lu expected): %s\n", + rand, state->check, + rand - state->check ? "*INCORRECT*" : "CORRECT"); + N(RandomDestroy)(state); + + printf("Checking periods...\n"); + check_period(1); + check_period(2); + check_period(31415926); + + return 0; +} +#endif diff --git a/src/mesa/drivers/dri/dri_client/xf86drmSL.c b/src/mesa/drivers/dri/dri_client/xf86drmSL.c new file mode 100644 index 00000000000..dd634c30f62 --- /dev/null +++ b/src/mesa/drivers/dri/dri_client/xf86drmSL.c @@ -0,0 +1,490 @@ +/* xf86drmSL.c -- Skip list support + * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith + * + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmSL.c,v 1.3 2000/06/17 00:03:34 martin Exp $ + * + * DESCRIPTION + * + * This file contains a straightforward skip list implementation.n + * + * FUTURE ENHANCEMENTS + * + * REFERENCES + * + * [Pugh90] William Pugh. Skip Lists: A Probabilistic Alternative to + * Balanced Trees. CACM 33(6), June 1990, pp. 668-676. + * + */ + +#define SL_MAIN 0 + +#if SL_MAIN +# include +# include +# include +#else +# include "xf86drm.h" +# ifdef XFree86LOADER +# include "xf86.h" +# include "xf86_ansic.h" +# else +# include +# include +# endif +#endif + +#define N(x) drm##x + +#define SL_LIST_MAGIC 0xfacade00LU +#define SL_ENTRY_MAGIC 0x00fab1edLU +#define SL_FREED_MAGIC 0xdecea5edLU +#define SL_MAX_LEVEL 16 +#define SL_DEBUG 0 +#define SL_RANDOM_SEED 0xc01055a1LU + +#if SL_MAIN +#define SL_ALLOC malloc +#define SL_FREE free +#define SL_RANDOM_DECL static int state = 0; +#define SL_RANDOM_INIT(seed) if (!state) { srandom(seed); ++state; } +#define SL_RANDOM random() +#else +#define SL_ALLOC drmMalloc +#define SL_FREE drmFree +#define SL_RANDOM_DECL static void *state = NULL +#define SL_RANDOM_INIT(seed) if (!state) state = drmRandomCreate(seed) +#define SL_RANDOM drmRandom(state) + +#endif + +typedef struct SLEntry { + unsigned long magic; /* SL_ENTRY_MAGIC */ + unsigned long key; + void *value; + int levels; + struct SLEntry *forward[1]; /* variable sized array */ +} SLEntry, *SLEntryPtr; + +typedef struct SkipList { + unsigned long magic; /* SL_LIST_MAGIC */ + int level; + int count; + SLEntryPtr head; + SLEntryPtr p0; /* Position for iteration */ +} SkipList, *SkipListPtr; + +#if SL_MAIN +extern void *N(SLCreate)(void); +extern int N(SLDestroy)(void *l); +extern int N(SLLookup)(void *l, unsigned long key, void **value); +extern int N(SLInsert)(void *l, unsigned long key, void *value); +extern int N(SLDelete)(void *l, unsigned long key); +extern int N(SLNext)(void *l, unsigned long *key, void **value); +extern int N(SLFirst)(void *l, unsigned long *key, void **value); +extern void N(SLDump)(void *l); +extern int N(SLLookupNeighbors)(void *l, unsigned long key, + unsigned long *prev_key, void **prev_value, + unsigned long *next_key, void **next_value); +#endif + +static SLEntryPtr SLCreateEntry(int max_level, unsigned long key, void *value) +{ + SLEntryPtr entry; + + if (max_level < 0 || max_level > SL_MAX_LEVEL) max_level = SL_MAX_LEVEL; + + entry = SL_ALLOC(sizeof(*entry) + + (max_level + 1) * sizeof(entry->forward[0])); + if (!entry) return NULL; + entry->magic = SL_ENTRY_MAGIC; + entry->key = key; + entry->value = value; + entry->levels = max_level + 1; + + return entry; +} + +static int SLRandomLevel(void) +{ + int level = 1; + SL_RANDOM_DECL; + + SL_RANDOM_INIT(SL_RANDOM_SEED); + + while ((SL_RANDOM & 0x01) && level < SL_MAX_LEVEL) ++level; + return level; +} + +void *N(SLCreate)(void) +{ + SkipListPtr list; + int i; + + list = SL_ALLOC(sizeof(*list)); + if (!list) return NULL; + list->magic = SL_LIST_MAGIC; + list->level = 0; + list->head = SLCreateEntry(SL_MAX_LEVEL, 0, NULL); + list->count = 0; + + for (i = 0; i <= SL_MAX_LEVEL; i++) list->head->forward[i] = NULL; + + return list; +} + +int N(SLDestroy)(void *l) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + SLEntryPtr next; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + for (entry = list->head; entry; entry = next) { + if (entry->magic != SL_ENTRY_MAGIC) return -1; /* Bad magic */ + next = entry->forward[0]; + entry->magic = SL_FREED_MAGIC; + SL_FREE(entry); + } + + list->magic = SL_FREED_MAGIC; + SL_FREE(list); + return 0; +} + +static SLEntryPtr SLLocate(void *l, unsigned long key, SLEntryPtr *update) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + int i; + + if (list->magic != SL_LIST_MAGIC) return NULL; + + for (i = list->level, entry = list->head; i >= 0; i--) { + while (entry->forward[i] && entry->forward[i]->key < key) + entry = entry->forward[i]; + update[i] = entry; + } + + return entry->forward[0]; +} + +int N(SLInsert)(void *l, unsigned long key, void *value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + int level; + int i; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + entry = SLLocate(list, key, update); + + if (entry && entry->key == key) return 1; /* Already in list */ + + + level = SLRandomLevel(); + if (level > list->level) { + level = ++list->level; + update[level] = list->head; + } + + entry = SLCreateEntry(level, key, value); + + /* Fix up forward pointers */ + for (i = 0; i <= level; i++) { + entry->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = entry; + } + + ++list->count; + return 0; /* Added to table */ +} + +int N(SLDelete)(void *l, unsigned long key) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + SLEntryPtr entry; + int i; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + entry = SLLocate(list, key, update); + + if (!entry || entry->key != key) return 1; /* Not found */ + + /* Fix up forward pointers */ + for (i = 0; i <= list->level; i++) { + if (update[i]->forward[i] == entry) + update[i]->forward[i] = entry->forward[i]; + } + + entry->magic = SL_FREED_MAGIC; + SL_FREE(entry); + + while (list->level && !list->head->forward[list->level]) --list->level; + --list->count; + return 0; +} + +int N(SLLookup)(void *l, unsigned long key, void **value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + SLEntryPtr entry; + + entry = SLLocate(list, key, update); + + if (entry && entry->key == key) { + *value = entry; + return 0; + } + *value = NULL; + return -1; +} + +int N(SLLookupNeighbors)(void *l, unsigned long key, + unsigned long *prev_key, void **prev_value, + unsigned long *next_key, void **next_value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + SLEntryPtr entry; + int retcode = 0; + + entry = SLLocate(list, key, update); + + *prev_key = *next_key = key; + *prev_value = *next_value = NULL; + + if (update[0]) { + *prev_key = update[0]->key; + *prev_value = update[0]->value; + ++retcode; + if (update[0]->forward[0]) { + *next_key = update[0]->forward[0]->key; + *next_value = update[0]->forward[0]->value; + ++retcode; + } + } + return retcode; +} + +int N(SLNext)(void *l, unsigned long *key, void **value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + entry = list->p0; + + if (entry) { + list->p0 = entry->forward[0]; + *key = entry->key; + *value = entry->value; + return 1; + } + list->p0 = NULL; + return 0; +} + +int N(SLFirst)(void *l, unsigned long *key, void **value) +{ + SkipListPtr list = (SkipListPtr)l; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + list->p0 = list->head->forward[0]; + return N(SLNext)(list, key, value); +} + +/* Dump internal data structures for debugging. */ +void N(SLDump)(void *l) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + int i; + + if (list->magic != SL_LIST_MAGIC) { + printf("Bad magic: 0x%08lx (expected 0x%08lx)\n", + list->magic, SL_LIST_MAGIC); + return; + } + + printf("Level = %d, count = %d\n", list->level, list->count); + for (entry = list->head; entry; entry = entry->forward[0]) { + if (entry->magic != SL_ENTRY_MAGIC) { + printf("Bad magic: 0x%08lx (expected 0x%08lx)\n", + list->magic, SL_ENTRY_MAGIC); + } + printf("\nEntry %p <0x%08lx, %p> has %2d levels\n", + entry, entry->key, entry->value, entry->levels); + for (i = 0; i < entry->levels; i++) { + if (entry->forward[i]) { + printf(" %2d: %p <0x%08lx, %p>\n", + i, + entry->forward[i], + entry->forward[i]->key, + entry->forward[i]->value); + } else { + printf(" %2d: %p\n", i, entry->forward[i]); + } + } + } +} + +#if SL_MAIN +static void print(SkipListPtr list) +{ + unsigned long key; + void *value; + + if (N(SLFirst)(list, &key, &value)) { + do { + printf("key = %5lu, value = %p\n", key, value); + } while (N(SLNext)(list, &key, &value)); + } +} + +static double do_time(int size, int iter) +{ + SkipListPtr list; + int i, j; + unsigned long keys[1000000]; + unsigned long previous; + unsigned long key; + void *value; + struct timeval start, stop; + double usec; + SL_RANDOM_DECL; + + SL_RANDOM_INIT(12345); + + list = N(SLCreate)(); + + for (i = 0; i < size; i++) { + keys[i] = SL_RANDOM; + N(SLInsert)(list, keys[i], NULL); + } + + previous = 0; + if (N(SLFirst)(list, &key, &value)) { + do { + if (key <= previous) { + printf( "%lu !< %lu\n", previous, key); + } + previous = key; + } while (N(SLNext)(list, &key, &value)); + } + + gettimeofday(&start, NULL); + for (j = 0; j < iter; j++) { + for (i = 0; i < size; i++) { + if (N(SLLookup)(list, keys[i], &value)) + printf("Error %lu %d\n", keys[i], i); + } + } + gettimeofday(&stop, NULL); + + usec = (double)(stop.tv_sec * 1000000 + stop.tv_usec + - start.tv_sec * 1000000 - start.tv_usec) / (size * iter); + + printf("%0.2f microseconds for list length %d\n", usec, size); + + N(SLDestroy)(list); + + return usec; +} + +static void print_neighbors(void *list, unsigned long key) +{ + unsigned long prev_key = 0; + unsigned long next_key = 0; + void *prev_value; + void *next_value; + int retval; + + retval = drmSLLookupNeighbors(list, key, + &prev_key, &prev_value, + &next_key, &next_value); + printf("Neighbors of %5lu: %d %5lu %5lu\n", + key, retval, prev_key, next_key); +} + +int main(void) +{ + SkipListPtr list; + double usec, usec2, usec3, usec4; + + list = N(SLCreate)(); + printf( "list at %p\n", list); + + print(list); + printf("\n==============================\n\n"); + + N(SLInsert)(list, 123, NULL); + N(SLInsert)(list, 213, NULL); + N(SLInsert)(list, 50, NULL); + print(list); + printf("\n==============================\n\n"); + + print_neighbors(list, 0); + print_neighbors(list, 50); + print_neighbors(list, 51); + print_neighbors(list, 123); + print_neighbors(list, 200); + print_neighbors(list, 213); + print_neighbors(list, 256); + printf("\n==============================\n\n"); + + N(SLDelete)(list, 50); + print(list); + printf("\n==============================\n\n"); + + N(SLDump)(list); + N(SLDestroy)(list); + printf("\n==============================\n\n"); + + usec = do_time(100, 10000); + usec2 = do_time(1000, 500); + printf("Table size increased by %0.2f, search time increased by %0.2f\n", + 1000.0/100.0, usec2 / usec); + + usec3 = do_time(10000, 50); + printf("Table size increased by %0.2f, search time increased by %0.2f\n", + 10000.0/100.0, usec3 / usec); + + usec4 = do_time(100000, 4); + printf("Table size increased by %0.2f, search time increased by %0.2f\n", + 100000.0/100.0, usec4 / usec); + + return 0; +} +#endif