summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/glx/x11/dri2.c252
-rw-r--r--src/glx/x11/dri2.h53
-rw-r--r--src/glx/x11/dri2_glx.c371
-rw-r--r--src/glx/x11/dri_common.c399
-rw-r--r--src/glx/x11/dri_common.h60
-rw-r--r--src/glx/x11/glxcurrent.c510
-rw-r--r--src/glx/x11/glxhash.c416
-rw-r--r--src/glx/x11/glxhash.h16
-rw-r--r--src/glx/x11/indirect_texture_compression.c347
-rw-r--r--src/glx/x11/indirect_vertex_array_priv.h308
10 files changed, 2732 insertions, 0 deletions
diff --git a/src/glx/x11/dri2.c b/src/glx/x11/dri2.c
new file mode 100644
index 0000000000..e7044ab424
--- /dev/null
+++ b/src/glx/x11/dri2.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh@redhat.com)
+ */
+
+
+#define NEED_REPLIES
+#include <X11/Xlibint.h>
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+#include <X11/extensions/dri2proto.h>
+#include "glheader.h"
+#include "xf86drm.h"
+#include "dri2.h"
+
+static char dri2ExtensionName[] = DRI2_NAME;
+static XExtensionInfo *dri2Info;
+static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
+static /* const */ XExtensionHooks dri2ExtensionHooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ DRI2CloseDisplay, /* close_display */
+ NULL, /* wire_to_event */
+ NULL, /* event_to_wire */
+ NULL, /* error */
+ NULL, /* error_string */
+};
+
+static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay, dri2Info,
+ dri2ExtensionName,
+ &dri2ExtensionHooks,
+ 0, NULL)
+
+Bool DRI2QueryExtension(Display *dpy, int *eventBase, int *errorBase)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+
+ if (XextHasExtension(info)) {
+ *eventBase = info->codes->first_event;
+ *errorBase = info->codes->first_error;
+ return True;
+ }
+
+ return False;
+}
+
+Bool DRI2QueryVersion(Display *dpy, int *major, int *minor)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay (dpy);
+ xDRI2QueryVersionReply rep;
+ xDRI2QueryVersionReq *req;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2QueryVersion, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2QueryVersion;
+ req->majorVersion = DRI2_MAJOR;
+ req->minorVersion = DRI2_MINOR;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ *major = rep.majorVersion;
+ *minor = rep.minorVersion;
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return True;
+}
+
+Bool DRI2Connect(Display *dpy, int screen,
+ char **driverName, char **busId, unsigned int *sareaHandle)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2ConnectReply rep;
+ xDRI2ConnectReq *req;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2Connect, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2Connect;
+ req->screen = screen;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ *sareaHandle = rep.sareaHandle;
+
+ *driverName = Xmalloc(rep.driverNameLength + 1);
+ if (*driverName == NULL) {
+ _XEatData(dpy,
+ ((rep.driverNameLength + 3) & ~3) +
+ ((rep.busIdLength + 3) & ~3));
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ _XReadPad(dpy, *driverName, rep.driverNameLength);
+ (*driverName)[rep.driverNameLength] = '\0';
+
+ *busId = Xmalloc(rep.busIdLength + 1);
+ if (*busId == NULL) {
+ Xfree(*driverName);
+ _XEatData(dpy, ((rep.busIdLength + 3) & ~3));
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ _XReadPad(dpy, *busId, rep.busIdLength);
+ (*busId)[rep.busIdLength] = '\0';
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return rep.sareaHandle != 0;
+}
+
+Bool DRI2AuthConnection(Display *dpy, int screen, drm_magic_t magic)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2AuthConnectionReq *req;
+ xDRI2AuthConnectionReply rep;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2AuthConnection, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2AuthConnection;
+ req->screen = screen;
+ req->magic = magic;
+ rep.authenticated = 0;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return rep.authenticated;
+}
+
+Bool DRI2CreateDrawable(Display *dpy, XID drawable,
+ unsigned int *handle, unsigned int *head)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2CreateDrawableReply rep;
+ xDRI2CreateDrawableReq *req;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2CreateDrawable, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2CreateDrawable;
+ req->drawable = drawable;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ *handle = rep.handle;
+ *head = rep.head;
+
+ return True;
+}
+
+void DRI2DestroyDrawable(Display *dpy, XID drawable)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2DestroyDrawableReq *req;
+
+ XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
+
+ XSync(dpy, GL_FALSE);
+
+ LockDisplay(dpy);
+ GetReq(DRI2DestroyDrawable, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2DestroyDrawable;
+ req->drawable = drawable;
+ UnlockDisplay(dpy);
+ SyncHandle();
+}
+
+Bool DRI2ReemitDrawableInfo(Display *dpy, XID drawable, unsigned int *head)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2ReemitDrawableInfoReply rep;
+ xDRI2ReemitDrawableInfoReq *req;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2ReemitDrawableInfo, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2ReemitDrawableInfo;
+ req->drawable = drawable;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ *head = rep.head;
+
+ return True;
+}
diff --git a/src/glx/x11/dri2.h b/src/glx/x11/dri2.h
new file mode 100644
index 0000000000..1dfd0448b2
--- /dev/null
+++ b/src/glx/x11/dri2.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2007,2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh@redhat.com)
+ */
+
+#ifndef _DRI2_H_
+#define _DRI2_H_
+
+extern Bool
+DRI2QueryExtension(Display *display, int *eventBase, int *errorBase);
+extern Bool
+DRI2QueryVersion(Display *display, int *major, int *minor);
+extern Bool
+DRI2Connect(Display *display, int screen,
+ char **driverName, char **busId, unsigned int *sareaHandle);
+extern Bool
+DRI2AuthConnection(Display *display, int screen, drm_magic_t magic);
+extern Bool
+DRI2CreateDrawable(Display *display, XID drawable,
+ unsigned int *handle, unsigned int *head);
+extern void
+DRI2DestroyDrawable(Display *display, XID handle);
+extern Bool
+DRI2ReemitDrawableInfo(Display *dpy, XID handle, unsigned int *head);
+
+#endif
diff --git a/src/glx/x11/dri2_glx.c b/src/glx/x11/dri2_glx.c
new file mode 100644
index 0000000000..b679c72c10
--- /dev/null
+++ b/src/glx/x11/dri2_glx.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh@redhat.com)
+ */
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/Xdamage.h>
+#include "glheader.h"
+#include "glxclient.h"
+#include "glcontextmodes.h"
+#include "xf86dri.h"
+#include "sarea.h"
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include "xf86drm.h"
+#include "dri2.h"
+#include "dri_common.h"
+
+typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
+typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
+
+struct __GLXDRIdisplayPrivateRec {
+ __GLXDRIdisplay base;
+
+ /*
+ ** XFree86-DRI version information
+ */
+ int driMajor;
+ int driMinor;
+ int driPatch;
+};
+
+struct __GLXDRIcontextPrivateRec {
+ __GLXDRIcontext base;
+ __DRIcontext *driContext;
+ __GLXscreenConfigs *psc;
+};
+
+static void dri2DestroyContext(__GLXDRIcontext *context,
+ __GLXscreenConfigs *psc, Display *dpy)
+{
+ __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
+ const __DRIcoreExtension *core = pcp->psc->core;
+
+ (*core->destroyContext)(pcp->driContext);
+
+ Xfree(pcp);
+}
+
+static Bool dri2BindContext(__GLXDRIcontext *context,
+ __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
+{
+ __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
+ const __DRIcoreExtension *core = pcp->psc->core;
+
+ return (*core->bindContext)(pcp->driContext,
+ draw->driDrawable,
+ read->driDrawable);
+}
+
+static void dri2UnbindContext(__GLXDRIcontext *context)
+{
+ __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
+ const __DRIcoreExtension *core = pcp->psc->core;
+
+ (*core->unbindContext)(pcp->driContext);
+}
+
+static __GLXDRIcontext *dri2CreateContext(__GLXscreenConfigs *psc,
+ const __GLcontextModes *mode,
+ GLXContext gc,
+ GLXContext shareList, int renderType)
+{
+ __GLXDRIcontextPrivate *pcp, *pcp_shared;
+ __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
+ const __DRIcoreExtension *core = psc->core;
+ __DRIcontext *shared = NULL;
+
+ if (shareList) {
+ pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
+ shared = pcp_shared->driContext;
+ }
+
+ pcp = Xmalloc(sizeof *pcp);
+ if (pcp == NULL)
+ return NULL;
+
+ pcp->psc = psc;
+ pcp->driContext =
+ (*core->createNewContext)(psc->__driScreen,
+ config->driConfig, shared, pcp);
+ gc->__driContext = pcp->driContext;
+
+ if (pcp->driContext == NULL) {
+ Xfree(pcp);
+ return NULL;
+ }
+
+ pcp->base.destroyContext = dri2DestroyContext;
+ pcp->base.bindContext = dri2BindContext;
+ pcp->base.unbindContext = dri2UnbindContext;
+
+ return &pcp->base;
+}
+
+static void dri2DestroyDrawable(__GLXDRIdrawable *pdraw)
+{
+ const __DRIcoreExtension *core = pdraw->psc->core;
+
+ (*core->destroyDrawable)(pdraw->driDrawable);
+ DRI2DestroyDrawable(pdraw->psc->dpy, pdraw->drawable);
+ Xfree(pdraw);
+}
+
+static __GLXDRIdrawable *dri2CreateDrawable(__GLXscreenConfigs *psc,
+ XID xDrawable,
+ GLXDrawable drawable,
+ const __GLcontextModes *modes)
+{
+ __GLXDRIdrawable *pdraw;
+ __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
+ unsigned int handle, head;
+ const __DRIcoreExtension *core = psc->core;
+
+ pdraw = Xmalloc(sizeof(*pdraw));
+ if (!pdraw)
+ return NULL;
+
+ pdraw->destroyDrawable = dri2DestroyDrawable;
+ pdraw->xDrawable = xDrawable;
+ pdraw->drawable = drawable;
+ pdraw->psc = psc;
+
+ fprintf(stderr, "calling DRI2CreateDrawable, XID 0x%lx, GLX ID 0x%lx\n",
+ xDrawable, drawable);
+
+ if (!DRI2CreateDrawable(psc->dpy, xDrawable, &handle, &head)) {
+ Xfree(pdraw);
+ return NULL;
+ }
+
+ fprintf(stderr, "success, head 0x%x, handle 0x%x\n", head, handle);
+
+ /* Create a new drawable */
+ pdraw->driDrawable =
+ (*core->createNewDrawable)(psc->__driScreen,
+ config->driConfig,
+ handle,
+ head,
+ pdraw);
+
+ if (!pdraw->driDrawable) {
+ DRI2DestroyDrawable(psc->dpy, drawable);
+ Xfree(pdraw);
+ return NULL;
+ }
+
+ return pdraw;
+}
+
+static void dri2DestroyScreen(__GLXscreenConfigs *psc)
+{
+ /* Free the direct rendering per screen data */
+ (*psc->core->destroyScreen)(psc->__driScreen);
+ drmClose(psc->fd);
+ psc->__driScreen = NULL;
+}
+
+
+static void dri2ReemitDrawableInfo(__DRIdrawable *draw, unsigned int *tail,
+ void *loaderPrivate)
+{
+ __GLXDRIdrawable *pdraw = loaderPrivate;
+
+ DRI2ReemitDrawableInfo(pdraw->psc->dpy, pdraw->drawable, tail);
+}
+
+static void dri2PostDamage(__DRIdrawable *draw,
+ struct drm_clip_rect *rects,
+ int numRects, void *loaderPrivate)
+{
+ XRectangle *xrects;
+ XserverRegion region;
+ __GLXDRIdrawable *glxDraw = loaderPrivate;
+ __GLXscreenConfigs *psc = glxDraw->psc;
+ Display *dpy = psc->dpy;
+ int i;
+
+ xrects = malloc(sizeof(XRectangle) * numRects);
+ if (xrects == NULL)
+ return;
+
+ for (i = 0; i < numRects; i++) {
+ xrects[i].x = rects[i].x1;
+ xrects[i].y = rects[i].y1;
+ xrects[i].width = rects[i].x2 - rects[i].x1;
+ xrects[i].height = rects[i].y2 - rects[i].y1;
+ }
+ region = XFixesCreateRegion(dpy, xrects, numRects);
+ free(xrects);
+ XDamageAdd(dpy, glxDraw->xDrawable, region);
+ XFixesDestroyRegion(dpy, region);
+}
+
+static const __DRIloaderExtension dri2LoaderExtension = {
+ { __DRI_LOADER, __DRI_LOADER_VERSION },
+ dri2ReemitDrawableInfo,
+ dri2PostDamage
+};
+
+static const __DRIextension *loader_extensions[] = {
+ &dri2LoaderExtension.base,
+ &systemTimeExtension.base,
+ NULL
+};
+
+static __GLXDRIscreen *dri2CreateScreen(__GLXscreenConfigs *psc, int screen,
+ __GLXdisplayPrivate *priv)
+{
+ const __DRIconfig **driver_configs;
+ const __DRIextension **extensions;
+ __GLXDRIscreen *psp;
+ unsigned int sareaHandle;
+ char *driverName, *busID;
+ drm_magic_t magic;
+ int i;
+
+ psp = Xmalloc(sizeof *psp);
+ if (psp == NULL)
+ return NULL;
+
+ /* Initialize per screen dynamic client GLX extensions */
+ psc->ext_list_first_time = GL_TRUE;
+
+ if (!DRI2Connect(psc->dpy, screen, &driverName, &busID, &sareaHandle))
+ return NULL;
+
+ psc->driver = driOpenDriver(driverName);
+ if (psc->driver == NULL)
+ goto handle_error;
+
+ extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
+ if (extensions == NULL) {
+ ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
+ goto handle_error;
+ }
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
+ psc->core = (__DRIcoreExtension *) extensions[i];
+ }
+
+ if (psc->core == NULL) {
+ ErrorMessageF("core dri extension not found\n");
+ goto handle_error;
+ }
+
+ psc->fd = drmOpen(NULL, busID);
+ if (psc->fd < 0) {
+ ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ if (drmGetMagic(psc->fd, &magic))
+ return NULL;
+
+ if (!DRI2AuthConnection(psc->dpy, screen, magic)) {
+ ErrorMessageF("failed to authenticate drm access\n");
+ return NULL;
+ }
+
+ psc->__driScreen =
+ psc->core->createNewScreen(screen, psc->fd, sareaHandle,
+ loader_extensions, &driver_configs, psc);
+ if (psc->__driScreen == NULL) {
+ ErrorMessageF("failed to create dri screen\n");
+ return NULL;
+ }
+
+ driBindExtensions(psc);
+
+ psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs);
+ psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs);
+
+ psp->destroyScreen = dri2DestroyScreen;
+ psp->createContext = dri2CreateContext;
+ psp->createDrawable = dri2CreateDrawable;
+
+ Xfree(driverName);
+ Xfree(busID);
+
+ return psp;
+
+ handle_error:
+ Xfree(driverName);
+ Xfree(busID);
+
+ /* FIXME: clean up here */
+
+ return NULL;
+}
+
+/* Called from __glXFreeDisplayPrivate.
+ */
+static void dri2DestroyDisplay(__GLXDRIdisplay *dpy)
+{
+ Xfree(dpy);
+}
+
+/*
+ * Allocate, initialize and return a __DRIdisplayPrivate object.
+ * This is called from __glXInitialize() when we are given a new
+ * display pointer.
+ */
+_X_HIDDEN __GLXDRIdisplay *dri2CreateDisplay(Display *dpy)
+{
+ __GLXDRIdisplayPrivate *pdp;
+ int eventBase, errorBase;
+
+ if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
+ return NULL;
+
+ pdp = Xmalloc(sizeof *pdp);
+ if (pdp == NULL)
+ return NULL;
+
+ if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
+ Xfree(pdp);
+ return NULL;
+ }
+
+ pdp->driPatch = 0;
+
+ pdp->base.destroyDisplay = dri2DestroyDisplay;
+ pdp->base.createScreen = dri2CreateScreen;
+
+ return &pdp->base;
+}
+
+#endif /* GLX_DIRECT_RENDERING */
diff --git a/src/glx/x11/dri_common.c b/src/glx/x11/dri_common.c
new file mode 100644
index 0000000000..b159d193a5
--- /dev/null
+++ b/src/glx/x11/dri_common.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kevin E. Martin <kevin@precisioninsight.com>
+ * Brian Paul <brian@precisioninsight.com>
+ * Kristian Høgsberg (krh@redhat.com)
+ */
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <unistd.h>
+#include <dlfcn.h>
+#include "glheader.h"
+#include "glxclient.h"
+#include "glcontextmodes.h"
+#include "dri_common.h"
+
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+_X_HIDDEN 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);
+ }
+}
+
+/**
+ * Print error to stderr, unless LIBGL_DEBUG=="quiet".
+ */
+_X_HIDDEN void ErrorMessageF(const char *f, ...)
+{
+ va_list args;
+ const char *env;
+
+ if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
+ fprintf(stderr, "libGL error: ");
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ }
+}
+
+#ifndef DEFAULT_DRIVER_DIR
+/* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
+#define DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
+#endif
+
+/**
+ * Try to \c dlopen the named driver.
+ *
+ * This function adds the "_dri.so" suffix to the driver name and searches the
+ * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
+ * order to find the driver.
+ *
+ * \param driverName - a name like "tdfx", "i810", "mga", etc.
+ *
+ * \returns
+ * A handle from \c dlopen, or \c NULL if driver file not found.
+ */
+_X_HIDDEN void *driOpenDriver(const char *driverName)
+{
+ void *glhandle, *handle;
+ const char *libPaths, *p, *next;
+ char realDriverName[200];
+ int len;
+
+ /* Attempt to make sure libGL symbols will be visible to the driver */
+ glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
+
+ libPaths = NULL;
+ 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 == NULL)
+ libPaths = DEFAULT_DRIVER_DIR;
+
+ handle = NULL;
+ for (p = libPaths; *p; p = next) {
+ next = strchr(p, ':');
+ if (next == NULL) {
+ len = strlen(p);
+ next = p + len;
+ } else {
+ len = next - p;
+ next++;
+ }
+
+#ifdef GLX_USE_TLS
+ snprintf(realDriverName, sizeof realDriverName,
+ "%.*s/tls/%s_dri.so", len, p, driverName);
+ InfoMessageF("OpenDriver: trying %s\n", realDriverName);
+ handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
+#endif
+
+ if ( handle == NULL ) {
+ snprintf(realDriverName, sizeof realDriverName,
+ "%.*s/%s_dri.so", len, p, driverName);
+ InfoMessageF("OpenDriver: trying %s\n", realDriverName);
+ handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
+ }
+
+ if ( handle != NULL )
+ break;
+ else
+ ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
+ }
+
+ if (!handle)
+ ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
+
+ if (glhandle)
+ dlclose(glhandle);
+
+ return handle;
+}
+
+_X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = {
+ { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
+ __glXGetUST,
+ __driGetMscRateOML
+};
+
+#define __ATTRIB(attrib, field) \
+ { attrib, offsetof(__GLcontextModes, field) }
+
+static const struct { unsigned int attrib, offset; } attribMap[] = {
+ __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
+ __ATTRIB(__DRI_ATTRIB_LEVEL, level),
+ __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
+ __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
+ __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
+ __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
+ __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
+ __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
+ __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
+ __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
+ __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
+ __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
+ __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
+ __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
+#if 0
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
+ __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
+ __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
+ __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
+ __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
+ __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
+#endif
+ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
+ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
+ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
+ __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
+ __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
+#if 0
+ __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
+#endif
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
+ __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
+ __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
+};
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+static int
+scalarEqual(__GLcontextModes *mode, unsigned int attrib, unsigned int value)
+{
+ unsigned int glxValue;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(attribMap); i++)
+ if (attribMap[i].attrib == attrib) {
+ glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
+ return glxValue == GLX_DONT_CARE || glxValue == value;
+ }
+
+ return GL_TRUE; /* Is a non-existing attribute equal to value? */
+}
+
+static int
+driConfigEqual(const __DRIcoreExtension *core,
+ __GLcontextModes *modes, const __DRIconfig *driConfig)
+{
+ unsigned int attrib, value, glxValue;
+ int i;
+
+ i = 0;
+ while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
+ switch (attrib) {
+ case __DRI_ATTRIB_RENDER_TYPE:
+ glxValue = 0;
+ if (value & __DRI_ATTRIB_RGBA_BIT) {
+ glxValue |= GLX_RGBA_BIT;
+ } else if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
+ glxValue |= GLX_COLOR_INDEX_BIT;
+ }
+ if (glxValue != modes->renderType)
+ return GL_FALSE;
+ break;
+
+ case __DRI_ATTRIB_CONFIG_CAVEAT:
+ if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
+ glxValue = GLX_NON_CONFORMANT_CONFIG;
+ else if (value & __DRI_ATTRIB_SLOW_BIT)
+ glxValue = GLX_SLOW_CONFIG;
+ else
+ glxValue = GLX_NONE;
+ if (glxValue != modes->visualRating)
+ return GL_FALSE;
+ break;
+
+ case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
+ glxValue = 0;
+ if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
+ glxValue |= GLX_TEXTURE_1D_BIT_EXT;
+ if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
+ glxValue |= GLX_TEXTURE_2D_BIT_EXT;
+ if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
+ glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
+ if (modes->bindToTextureTargets != GLX_DONT_CARE &&
+ glxValue != modes->bindToTextureTargets)
+ return GL_FALSE;
+ break;
+
+ default:
+ if (!scalarEqual(modes, attrib, value))
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+static __GLcontextModes *
+createDriMode(const __DRIcoreExtension *core,
+ __GLcontextModes *modes, const __DRIconfig **driConfigs)
+{
+ __GLXDRIconfigPrivate *config;
+ int i;
+
+ for (i = 0; driConfigs[i]; i++) {
+ if (driConfigEqual(core, modes, driConfigs[i]))
+ break;
+ }
+
+ if (driConfigs[i] == NULL)
+ return NULL;
+
+ config = Xmalloc(sizeof *config);
+ if (config == NULL)
+ return NULL;
+
+ config->modes = *modes;
+ config->driConfig = driConfigs[i];
+
+ return &config->modes;
+}
+
+_X_HIDDEN __GLcontextModes *
+driConvertConfigs(const __DRIcoreExtension *core,
+ __GLcontextModes *modes, const __DRIconfig **configs)
+{
+ __GLcontextModes head, *tail, *m;
+
+ tail = &head;
+ head.next = NULL;
+ for (m = modes; m; m = m->next) {
+ tail->next = createDriMode(core, m, configs);
+ if (tail->next == NULL) {
+ /* no matching dri config for m */
+ continue;
+ }
+
+
+ tail = tail->next;
+ }
+
+ _gl_context_modes_destroy(modes);
+
+ return head.next;
+}
+
+_X_HIDDEN void
+driBindExtensions(__GLXscreenConfigs *psc)
+{
+ const __DRIextension **extensions;
+ int i;
+
+ extensions = psc->core->getExtensions(psc->__driScreen);
+
+ for (i = 0; extensions[i]; i++) {
+#ifdef __DRI_COPY_SUB_BUFFER
+ if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
+ psc->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
+ __glXEnableDirectExtension(psc, "GLX_MESA_copy_sub_buffer_bit");
+ }
+#endif
+
+#ifdef __DRI_SWAP_CONTROL
+ if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
+ psc->swapControl = (__DRIswapControlExtension *) extensions[i];
+ __glXEnableDirectExtension(psc, "GLX_SGI_swap_control");
+ __glXEnableDirectExtension(psc, "GLX_MESA_swap_control");
+ }
+#endif
+
+#ifdef __DRI_ALLOCATE
+ if (strcmp(extensions[i]->name, __DRI_ALLOCATE) == 0) {
+ psc->allocate = (__DRIallocateExtension *) extensions[i];
+ __glXEnableDirectExtension(psc, "GLX_MESA_allocate_memory");
+ }
+#endif
+
+#ifdef __DRI_FRAME_TRACKING
+ if (strcmp(extensions[i]->name, __DRI_FRAME_TRACKING) == 0) {
+ psc->frameTracking = (__DRIframeTrackingExtension *) extensions[i];
+ __glXEnableDirectExtension(psc, "GLX_MESA_swap_frame_usage");
+ }
+#endif
+
+#ifdef __DRI_MEDIA_STREAM_COUNTER
+ if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
+ psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
+ __glXEnableDirectExtension(psc, "GLX_SGI_video_sync");
+ }
+#endif
+
+#ifdef __DRI_SWAP_BUFFER_COUNTER
+ /* No driver supports this at this time and the extension is
+ * not defined in dri_interface.h. Will enable
+ * GLX_OML_sync_control if implemented. */
+#endif
+
+#ifdef __DRI_READ_DRAWABLE
+ if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
+ __glXEnableDirectExtension(psc, "GLX_SGI_make_current_read");
+ }
+#endif
+
+#ifdef __DRI_TEX_BUFFER
+ if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
+ psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
+ __glXEnableDirectExtension(psc, "GLX_EXT_texture_from_pixmap");
+ }
+#endif
+
+ /* Ignore unknown extensions */
+ }
+}
+
+#endif /* GLX_DIRECT_RENDERING */
diff --git a/src/glx/x11/dri_common.h b/src/glx/x11/dri_common.h
new file mode 100644
index 0000000000..3556510335
--- /dev/null
+++ b/src/glx/x11/dri_common.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kevin E. Martin <kevin@precisioninsight.com>
+ * Brian Paul <brian@precisioninsight.com>
+ * Kristian Høgsberg (krh@redhat.com)
+ */
+
+#ifndef _DRI_COMMON_H
+#define _DRI_COMMON_H
+
+typedef struct __GLXDRIconfigPrivateRec __GLXDRIconfigPrivate;
+
+struct __GLXDRIconfigPrivateRec {
+ __GLcontextModes modes;
+ const __DRIconfig *driConfig;
+};
+
+extern __GLcontextModes *
+driConvertConfigs(const __DRIcoreExtension *core,
+ __GLcontextModes *modes, const __DRIconfig **configs);
+
+extern const __DRIsystemTimeExtension systemTimeExtension;
+
+extern void InfoMessageF(const char *f, ...);
+
+extern void ErrorMessageF(const char *f, ...);
+
+extern void *driOpenDriver(const char *driverName);
+
+extern void driBindExtensions(__GLXscreenConfigs *psc);
+
+#endif /* _DRI_COMMON_H */
diff --git a/src/glx/x11/glxcurrent.c b/src/glx/x11/glxcurrent.c
new file mode 100644
index 0000000000..ad648fd438
--- /dev/null
+++ b/src/glx/x11/glxcurrent.c
@@ -0,0 +1,510 @@
+/*
+** 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.
+**
+*/
+
+/**
+ * \file glxcurrent.c
+ * Client-side GLX interface for current context management.
+ */
+
+#include "glxclient.h"
+#include "glapi.h"
+#include "glheader.h"
+#include "indirect_init.h"
+
+#ifdef GLX_DIRECT_RENDERING
+#include "xf86dri.h"
+#endif
+
+/*
+** We setup some dummy structures here so that the API can be used
+** even if no context is current.
+*/
+
+static GLubyte dummyBuffer[__GLX_BUFFER_LIMIT_SIZE];
+
+/*
+** Dummy context used by small commands when there is no current context.
+** All the
+** gl and glx entry points are designed to operate as nop's when using
+** the dummy context structure.
+*/
+static __GLXcontext dummyContext = {
+ &dummyBuffer[0],
+ &dummyBuffer[0],
+ &dummyBuffer[0],
+ &dummyBuffer[__GLX_BUFFER_LIMIT_SIZE],
+ sizeof(dummyBuffer),
+};
+
+
+/*
+** All indirect rendering contexts will share the same indirect dispatch table.
+*/
+static __GLapi *IndirectAPI = NULL;
+
+
+/*
+ * Current context management and locking
+ */
+
+#if defined( USE_XTHREADS )
+
+/* thread safe */
+static GLboolean TSDinitialized = GL_FALSE;
+static xthread_key_t ContextTSD;
+
+_X_HIDDEN __GLXcontext *__glXGetCurrentContext(void)
+{
+ if (!TSDinitialized) {
+ xthread_key_create(&ContextTSD, NULL);
+ TSDinitialized = GL_TRUE;
+ return &dummyContext;
+ }
+ else {
+ void *p;
+ xthread_get_specific(ContextTSD, &p);
+ if (!p)
+ return &dummyContext;
+ else
+ return (__GLXcontext *) p;
+ }
+}
+
+_X_HIDDEN void __glXSetCurrentContext(__GLXcontext *c)
+{
+ if (!TSDinitialized) {
+ xthread_key_create(&ContextTSD, NULL);
+ TSDinitialized = GL_TRUE;
+ }
+ xthread_set_specific(ContextTSD, c);
+}
+
+
+/* Used by the __glXLock() and __glXUnlock() macros */
+_X_HIDDEN xmutex_rec __glXmutex;
+
+#elif defined( PTHREADS )
+
+_X_HIDDEN pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER;
+
+# if defined( GLX_USE_TLS )
+
+/**
+ * Per-thread GLX context pointer.
+ *
+ * \c __glXSetCurrentContext is written is such a way that this pointer can
+ * \b never be \c NULL. This is important! Because of this
+ * \c __glXGetCurrentContext can be implemented as trivial macro.
+ */
+__thread void * __glX_tls_Context __attribute__((tls_model("initial-exec")))
+ = &dummyContext;
+
+_X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c )
+{
+ __glX_tls_Context = (c != NULL) ? c : &dummyContext;
+}
+
+# else
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+/**
+ * Per-thread data key.
+ *
+ * Once \c init_thread_data has been called, the per-thread data key will
+ * take a value of \c NULL. As each new thread is created the default
+ * value, in that thread, will be \c NULL.
+ */
+static pthread_key_t ContextTSD;
+
+/**
+ * Initialize the per-thread data key.
+ *
+ * This function is called \b exactly once per-process (not per-thread!) to
+ * initialize the per-thread data key. This is ideally done using the
+ * \c pthread_once mechanism.
+ */
+static void init_thread_data( void )
+{
+ if ( pthread_key_create( & ContextTSD, NULL ) != 0 ) {
+ perror( "pthread_key_create" );
+ exit( -1 );
+ }
+}
+
+_X_HIDDEN void __glXSetCurrentContext( __GLXcontext * c )
+{
+ pthread_once( & once_control, init_thread_data );
+ pthread_setspecific( ContextTSD, c );
+}
+
+_X_HIDDEN __GLXcontext * __glXGetCurrentContext( void )
+{
+ void * v;
+
+ pthread_once( & once_control, init_thread_data );
+
+ v = pthread_getspecific( ContextTSD );
+ return (v == NULL) ? & dummyContext : (__GLXcontext *) v;
+}
+
+# endif /* defined( GLX_USE_TLS ) */
+
+#elif defined( THREADS )
+
+#error Unknown threading method specified.
+
+#else
+
+/* not thread safe */
+_X_HIDDEN __GLXcontext *__glXcurrentContext = &dummyContext;
+
+#endif
+
+
+_X_HIDDEN void __glXSetCurrentContextNull(void)
+{
+ __glXSetCurrentContext(&dummyContext);
+#ifdef GLX_DIRECT_RENDERING
+ _glapi_set_dispatch(NULL); /* no-op functions */
+#endif
+}
+
+
+/************************************************************************/
+
+PUBLIC GLXContext glXGetCurrentContext(void)
+{
+ GLXContext cx = __glXGetCurrentContext();
+
+ if (cx == &dummyContext) {
+ return NULL;
+ } else {
+ return cx;
+ }
+}
+
+PUBLIC GLXDrawable glXGetCurrentDrawable(void)
+{
+ GLXContext gc = __glXGetCurrentContext();
+ return gc->currentDrawable;
+}
+
+
+/************************************************************************/
+
+/**
+ * Sends a GLX protocol message to the specified display to make the context
+ * and the drawables current.
+ *
+ * \param dpy Display to send the message to.
+ * \param opcode Major opcode value for the display.
+ * \param gc_id Context tag for the context to be made current.
+ * \param draw Drawable ID for the "draw" drawable.
+ * \param read Drawable ID for the "read" drawable.
+ * \param reply Space to store the X-server's reply.
+ *
+ * \warning
+ * This function assumes that \c dpy is locked with \c LockDisplay on entry.
+ */
+static Bool SendMakeCurrentRequest(Display *dpy, CARD8 opcode,
+ GLXContextID gc_id, GLXContextTag gc_tag,
+ GLXDrawable draw, GLXDrawable read,
+ xGLXMakeCurrentReply *reply)
+{
+ Bool ret;
+
+
+ LockDisplay(dpy);
+
+ if (draw == read) {
+ xGLXMakeCurrentReq *req;
+
+ GetReq(GLXMakeCurrent,req);
+ req->reqType = opcode;
+ req->glxCode = X_GLXMakeCurrent;
+ req->drawable = draw;
+ req->context = gc_id;
+ req->oldContextTag = gc_tag;
+ }
+ else {
+ __GLXdisplayPrivate *priv = __glXInitialize(dpy);
+
+ /* If the server can support the GLX 1.3 version, we should
+ * perfer that. Not only that, some servers support GLX 1.3 but
+ * not the SGI extension.
+ */
+
+ if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
+ xGLXMakeContextCurrentReq *req;
+
+ GetReq(GLXMakeContextCurrent,req);
+ req->reqType = opcode;
+ req->glxCode = X_GLXMakeContextCurrent;
+ req->drawable = draw;
+ req->readdrawable = read;
+ req->context = gc_id;
+ req->oldContextTag = gc_tag;
+ }
+ else {
+ xGLXVendorPrivateWithReplyReq *vpreq;
+ xGLXMakeCurrentReadSGIReq *req;
+
+ GetReqExtra(GLXVendorPrivateWithReply,
+ sz_xGLXMakeCurrentReadSGIReq-sz_xGLXVendorPrivateWithReplyReq,vpreq);
+ req = (xGLXMakeCurrentReadSGIReq *)vpreq;
+ req->reqType = opcode;
+ req->glxCode = X_GLXVendorPrivateWithReply;
+ req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
+ req->drawable = draw;
+ req->readable = read;
+ req->context = gc_id;
+ req->oldContextTag = gc_tag;
+ }
+ }
+
+ ret = _XReply(dpy, (xReply*) reply, 0, False);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return ret;
+}
+
+
+#ifdef GLX_DIRECT_RENDERING
+static __GLXDRIdrawable *
+FetchDRIDrawable(Display *dpy,
+ GLXDrawable glxDrawable, GLXContext gc, Bool pre13)
+{
+ __GLXdisplayPrivate * const priv = __glXInitialize(dpy);
+ __GLXDRIdrawable *pdraw;
+ __GLXscreenConfigs *psc;
+ XID drawable;
+
+ if (priv == NULL)
+ return NULL;
+
+ psc = &priv->screenConfigs[gc->screen];
+ if (psc->drawHash == NULL)
+ return NULL;
+
+ if (__glxHashLookup(psc->drawHash, glxDrawable, (void *) &pdraw) == 0)
+ return pdraw;
+
+ /* If this is glXMakeCurrent (pre GLX 1.3) we allow creating the
+ * GLX drawable on the fly. Otherwise we pass None as the X
+ * drawable */
+ if (pre13)
+ drawable = glxDrawable;
+ else
+ drawable = None;
+
+ pdraw = psc->driScreen->createDrawable(psc, drawable,
+ glxDrawable, gc->mode);
+ if (__glxHashInsert(psc->drawHash, glxDrawable, pdraw)) {
+ (*pdraw->destroyDrawable)(pdraw);
+ return NULL;
+ }
+
+ return pdraw;
+}
+#endif /* GLX_DIRECT_RENDERING */
+
+
+/**
+ * Make a particular context current.
+ *
+ * \note This is in this file so that it can access dummyContext.
+ */
+static Bool MakeContextCurrent(Display *dpy, GLXDrawable draw,
+ GLXDrawable read, GLXContext gc,
+ Bool pre13)
+{
+ xGLXMakeCurrentReply reply;
+ const GLXContext oldGC = __glXGetCurrentContext();
+ const CARD8 opcode = __glXSetupForCommand(dpy);
+ const CARD8 oldOpcode = ((gc == oldGC) || (oldGC == &dummyContext))
+ ? opcode : __glXSetupForCommand(oldGC->currentDpy);
+ Bool bindReturnValue;
+
+
+ if (!opcode || !oldOpcode) {
+ return GL_FALSE;
+ }
+
+ /* Make sure that the new context has a nonzero ID. In the request,
+ * a zero context ID is used only to mean that we bind to no current
+ * context.
+ */
+ if ((gc != NULL) && (gc->xid == None)) {
+ return GL_FALSE;
+ }
+
+ _glapi_check_multithread();
+
+#ifdef GLX_DIRECT_RENDERING
+ /* Bind the direct rendering context to the drawable */
+ if (gc && gc->driContext) {
+ __GLXDRIdrawable *pdraw = FetchDRIDrawable(dpy, draw, gc, pre13);
+ __GLXDRIdrawable *pread = FetchDRIDrawable(dpy, read, gc, pre13);
+
+ bindReturnValue =
+ (gc->driContext->bindContext) (gc->driContext, pdraw, pread);
+ } else
+#endif
+ {
+ /* Send a glXMakeCurrent request to bind the new context. */
+ bindReturnValue =
+ SendMakeCurrentRequest(dpy, opcode, gc ? gc->xid : None,
+ ((dpy != oldGC->currentDpy) || oldGC->isDirect)
+ ? None : oldGC->currentContextTag,
+ draw, read, &reply);
+ }
+
+
+ if (!bindReturnValue) {
+ return False;
+ }
+
+ if ((dpy != oldGC->currentDpy || (gc && gc->driContext)) &&
+ !oldGC->isDirect && oldGC != &dummyContext) {
+ xGLXMakeCurrentReply dummy_reply;
+
+ /* We are either switching from one dpy to another and have to
+ * send a request to the previous dpy to unbind the previous
+ * context, or we are switching away from a indirect context to
+ * a direct context and have to send a request to the dpy to
+ * unbind the previous context.
+ */
+ (void) SendMakeCurrentRequest(oldGC->currentDpy, oldOpcode, None,
+ oldGC->currentContextTag, None, None,
+ & dummy_reply);
+ }
+#ifdef GLX_DIRECT_RENDERING
+ else if (oldGC->driContext) {
+ oldGC->driContext->unbindContext(oldGC->driContext);
+ }
+#endif
+
+
+ /* Update our notion of what is current */
+ __glXLock();
+ if (gc == oldGC) {
+ /* Even though the contexts are the same the drawable might have
+ * changed. Note that gc cannot be the dummy, and that oldGC
+ * cannot be NULL, therefore if they are the same, gc is not
+ * NULL and not the dummy.
+ */
+ gc->currentDrawable = draw;
+ gc->currentReadable = read;
+ } else {
+ if (oldGC != &dummyContext) {
+ /* Old current context is no longer current to anybody */
+ oldGC->currentDpy = 0;
+ oldGC->currentDrawable = None;
+ oldGC->currentReadable = None;
+ oldGC->currentContextTag = 0;
+
+ if (oldGC->xid == None) {
+ /* We are switching away from a context that was
+ * previously destroyed, so we need to free the memory
+ * for the old handle.
+ */
+#ifdef GLX_DIRECT_RENDERING
+ /* Destroy the old direct rendering context */
+ if (oldGC->driContext) {
+ oldGC->driContext->destroyContext(oldGC->driContext,
+ oldGC->psc,
+ oldGC->createDpy);
+ oldGC->driContext = NULL;
+ }
+#endif
+ __glXFreeContext(oldGC);
+ }
+ }
+ if (gc) {
+ __glXSetCurrentContext(gc);
+
+ gc->currentDpy = dpy;
+ gc->currentDrawable = draw;
+ gc->currentReadable = read;
+
+ if (!gc->driContext) {
+ if (!IndirectAPI)
+ IndirectAPI = __glXNewIndirectAPI();
+ _glapi_set_dispatch(IndirectAPI);
+
+#ifdef GLX_USE_APPLEGL
+ do {
+ extern void XAppleDRIUseIndirectDispatch(void);
+ XAppleDRIUseIndirectDispatch();
+ } while (0);
+#endif
+
+ __GLXattribute *state =
+ (__GLXattribute *)(gc->client_state_private);
+
+ gc->currentContextTag = reply.contextTag;
+ if (state->array_state == NULL) {
+ (void) glGetString(GL_EXTENSIONS);
+ (void) glGetString(GL_VERSION);
+ __glXInitVertexArrayState(gc);
+ }
+ }
+ else {
+ gc->currentContextTag = -1;
+ }
+ } else {
+ __glXSetCurrentContextNull();
+ }
+ }
+ __glXUnlock();
+ return GL_TRUE;
+}
+
+
+PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable draw, GLXContext gc)
+{
+ return MakeContextCurrent(dpy, draw, draw, gc, True);
+}
+
+PUBLIC GLX_ALIAS(Bool, glXMakeCurrentReadSGI,
+ (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
+ (dpy, d, r, ctx, False), MakeContextCurrent)
+
+PUBLIC GLX_ALIAS(Bool, glXMakeContextCurrent,
+ (Display *dpy, GLXDrawable d, GLXDrawable r, GLXContext ctx),
+ (dpy, d, r, ctx, False), MakeContextCurrent)
diff --git a/src/glx/x11/glxhash.c b/src/glx/x11/glxhash.c
new file mode 100644
index 0000000000..9ed0429032
--- /dev/null
+++ b/src/glx/x11/glxhash.c
@@ -0,0 +1,416 @@
+/* glxhash.c -- Small hash table support for integer -> integer mapping
+ * Taken from libdrm.
+ *
+ * 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 <faith@valinux.com>
+ *
+ * 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.
+ *
+ */
+
+#include "glxhash.h"
+#include <X11/Xfuncproto.h>
+
+#define HASH_MAIN 0
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#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! */
+
+#define HASH_ALLOC malloc
+#define HASH_FREE free
+#define HASH_RANDOM_DECL
+#define HASH_RANDOM_INIT(seed) srandom(seed)
+#define HASH_RANDOM random()
+#define HASH_RANDOM_DESTROY
+
+typedef struct __glxHashBucket {
+ unsigned long key;
+ void *value;
+ struct __glxHashBucket *next;
+} __glxHashBucket, *__glxHashBucketPtr;
+
+typedef struct __glxHashTable *__glxHashTablePtr;
+struct __glxHashTable {
+ 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 */
+ __glxHashBucketPtr buckets[HASH_SIZE];
+ int p0;
+ __glxHashBucketPtr p1;
+};
+
+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;
+ HASH_RANDOM_DESTROY;
+ ++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;
+}
+
+_X_HIDDEN __glxHashTable *__glxHashCreate(void)
+{
+ __glxHashTablePtr 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;
+}
+
+_X_HIDDEN int __glxHashDestroy(__glxHashTable *t)
+{
+ __glxHashTablePtr table = (__glxHashTablePtr)t;
+ __glxHashBucketPtr bucket;
+ __glxHashBucketPtr 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 __glxHashBucketPtr HashFind(__glxHashTablePtr table,
+ unsigned long key, unsigned long *h)
+{
+ unsigned long hash = HashHash(key);
+ __glxHashBucketPtr prev = NULL;
+ __glxHashBucketPtr 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;
+}
+
+_X_HIDDEN int __glxHashLookup(__glxHashTable *t,
+ unsigned long key, void **value)
+{
+ __glxHashTablePtr table = (__glxHashTablePtr)t;
+ __glxHashBucketPtr 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 */
+}
+
+_X_HIDDEN int __glxHashInsert(__glxHashTable *t,
+ unsigned long key, void *value)
+{
+ __glxHashTablePtr table = (__glxHashTablePtr)t;
+ __glxHashBucketPtr 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 */
+}
+
+_X_HIDDEN int __glxHashDelete(__glxHashTable *t, unsigned long key)
+{
+ __glxHashTablePtr table = (__glxHashTablePtr)t;
+ unsigned long hash;
+ __glxHashBucketPtr 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;
+}
+
+_X_HIDDEN int __glxHashNext(__glxHashTable *t,
+ unsigned long *key, void **value)
+{
+ __glxHashTablePtr table = (__glxHashTablePtr)t;
+
+ while (table->p0 < HASH_SIZE) {
+ if (table->p1) {
+ *key = table->p1->key;
+ *value = table->p1->value;
+ table->p1 = table->p1->next;
+ return 1;
+ }
+ table->p1 = table->buckets[table->p0];
+ ++table->p0;
+ }
+ return 0;
+}
+
+_X_HIDDEN int __glxHashFirst(__glxHashTable *t,
+ unsigned long *key, void **value)
+{
+ __glxHashTablePtr table = (__glxHashTablePtr)t;
+
+ if (table->magic != HASH_MAGIC) return -1; /* Bad magic */
+
+ table->p0 = 0;
+ table->p1 = table->buckets[0];
+ return __glxHashNext(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(__glxHashBucketPtr 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(__glxHashTablePtr table)
+{
+ int i;
+ __glxHashBucketPtr 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(__glxHashTablePtr table,
+ unsigned long key, unsigned long value)
+{
+ unsigned long retval = 0;
+ int retcode = __glxHashLookup(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)
+{
+ __glxHashTablePtr table;
+ int i;
+
+ printf("\n***** 256 consecutive integers ****\n");
+ table = __glxHashCreate();
+ for (i = 0; i < 256; i++) __glxHashInsert(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);
+ __glxHashDestroy(table);
+
+ printf("\n***** 1024 consecutive integers ****\n");
+ table = __glxHashCreate();
+ for (i = 0; i < 1024; i++) __glxHashInsert(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);
+ __glxHashDestroy(table);
+
+ printf("\n***** 1024 consecutive page addresses (4k pages) ****\n");
+ table = __glxHashCreate();
+ for (i = 0; i < 1024; i++) __glxHashInsert(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);
+ __glxHashDestroy(table);
+
+ printf("\n***** 1024 random integers ****\n");
+ table = __glxHashCreate();
+ srandom(0xbeefbeef);
+ for (i = 0; i < 1024; i++) __glxHashInsert(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);
+ __glxHashDestroy(table);
+
+ printf("\n***** 5000 random integers ****\n");
+ table = __glxHashCreate();
+ srandom(0xbeefbeef);
+ for (i = 0; i < 5000; i++) __glxHashInsert(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);
+ __glxHashDestroy(table);
+
+ return 0;
+}
+#endif
diff --git a/src/glx/x11/glxhash.h b/src/glx/x11/glxhash.h
new file mode 100644
index 0000000000..66012fb889
--- /dev/null
+++ b/src/glx/x11/glxhash.h
@@ -0,0 +1,16 @@
+#ifndef _GLX_HASH_H_
+#define _GLX_HASH_H_
+
+
+typedef struct __glxHashTable __glxHashTable;
+
+/* Hash table routines */
+extern __glxHashTable *__glxHashCreate(void);
+extern int __glxHashDestroy(__glxHashTable *t);
+extern int __glxHashLookup(__glxHashTable *t, unsigned long key, void **value);
+extern int __glxHashInsert(__glxHashTable *t, unsigned long key, void *value);
+extern int __glxHashDelete(__glxHashTable *t, unsigned long key);
+extern int __glxHashFirst(__glxHashTable *t, unsigned long *key, void **value);
+extern int __glxHashNext(__glxHashTable *t, unsigned long *key, void **value);
+
+#endif /* _GLX_HASH_H_ */
diff --git a/src/glx/x11/indirect_texture_compression.c b/src/glx/x11/indirect_texture_compression.c
new file mode 100644
index 0000000000..5676858017
--- /dev/null
+++ b/src/glx/x11/indirect_texture_compression.c
@@ -0,0 +1,347 @@
+/*
+ * (C) Copyright IBM Corporation 2004
+ * 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
+ * THE COPYRIGHT HOLDERS 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 glx_texture_compression.c
+ * Contains the routines required to implement GLX protocol for
+ * ARB_texture_compression and related extensions.
+ *
+ * \sa http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture_compression.txt
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include "packrender.h"
+#include "packsingle.h"
+#include "indirect.h"
+
+#include <assert.h>
+
+
+void
+__indirect_glGetCompressedTexImageARB( GLenum target, GLint level,
+ GLvoid * img )
+{
+ __GLX_SINGLE_DECLARE_VARIABLES();
+ xGLXGetTexImageReply reply;
+ size_t image_bytes;
+
+ __GLX_SINGLE_LOAD_VARIABLES();
+ __GLX_SINGLE_BEGIN( X_GLsop_GetCompressedTexImage, 8 );
+ __GLX_SINGLE_PUT_LONG( 0, target );
+ __GLX_SINGLE_PUT_LONG( 4, level );
+ __GLX_SINGLE_READ_XREPLY();
+
+ image_bytes = reply.width;
+ assert( image_bytes <= ((4 * reply.length) - 0) );
+ assert( image_bytes >= ((4 * reply.length) - 3) );
+
+ if ( image_bytes != 0 ) {
+ _XRead( dpy, (char *) img, image_bytes );
+ if ( image_bytes < (4 * reply.length) ) {
+ _XEatData( dpy, (4 * reply.length) - image_bytes );
+ }
+ }
+
+ __GLX_SINGLE_END();
+}
+
+
+/**
+ * Internal function used for \c glCompressedTexImage1D and
+ * \c glCompressedTexImage2D.
+ */
+static void
+CompressedTexImage1D2D( GLenum target, GLint level,
+ GLenum internal_format,
+ GLsizei width, GLsizei height,
+ GLint border, GLsizei image_size,
+ const GLvoid *data, CARD32 rop )
+{
+ __GLX_DECLARE_VARIABLES();
+
+ __GLX_LOAD_VARIABLES();
+ if ( gc->currentDpy == NULL ) {
+ return;
+ }
+
+ if ( (target == GL_PROXY_TEXTURE_1D)
+ || (target == GL_PROXY_TEXTURE_2D)
+ || (target == GL_PROXY_TEXTURE_CUBE_MAP) ) {
+ compsize = 0;
+ }
+ else {
+ compsize = image_size;
+ }
+
+ cmdlen = __GLX_PAD( __GLX_COMPRESSED_TEXIMAGE_CMD_HDR_SIZE
+ + compsize );
+ if ( cmdlen <= gc->maxSmallRenderCommandSize ) {
+ __GLX_BEGIN_VARIABLE( rop, cmdlen );
+ __GLX_PUT_LONG( 4, target );
+ __GLX_PUT_LONG( 8, level );
+ __GLX_PUT_LONG( 12, internal_format );
+ __GLX_PUT_LONG( 16, width );
+ __GLX_PUT_LONG( 20, height );
+ __GLX_PUT_LONG( 24, border );
+ __GLX_PUT_LONG( 28, image_size );
+ if ( compsize != 0 ) {
+ __GLX_PUT_CHAR_ARRAY( __GLX_COMPRESSED_TEXIMAGE_CMD_HDR_SIZE,
+ data, image_size );
+ }
+ __GLX_END( cmdlen );
+ }
+ else {
+ assert( compsize != 0 );
+
+ __GLX_BEGIN_VARIABLE_LARGE( rop, cmdlen + 4 );
+ __GLX_PUT_LONG( 8, target );
+ __GLX_PUT_LONG( 12, level );
+ __GLX_PUT_LONG( 16, internal_format );
+ __GLX_PUT_LONG( 20, width );
+ __GLX_PUT_LONG( 24, height );
+ __GLX_PUT_LONG( 28, border );
+ __GLX_PUT_LONG( 32, image_size );
+ __glXSendLargeCommand( gc, gc->pc,
+ __GLX_COMPRESSED_TEXIMAGE_CMD_HDR_SIZE + 4,
+ data, image_size );
+ }
+}
+
+
+/**
+ * Internal function used for \c glCompressedTexSubImage1D and
+ * \c glCompressedTexSubImage2D.
+ */
+static void
+CompressedTexSubImage1D2D( GLenum target, GLint level,
+ GLsizei xoffset, GLsizei yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLsizei image_size,
+ const GLvoid *data, CARD32 rop )
+{
+ __GLX_DECLARE_VARIABLES();
+
+ __GLX_LOAD_VARIABLES();
+ if ( gc->currentDpy == NULL ) {
+ return;
+ }
+
+ if ( target == GL_PROXY_TEXTURE_3D ) {
+ compsize = 0;
+ }
+ else {
+ compsize = image_size;
+ }
+
+ cmdlen = __GLX_PAD( __GLX_COMPRESSED_TEXSUBIMAGE_CMD_HDR_SIZE
+ + compsize );
+ if ( cmdlen <= gc->maxSmallRenderCommandSize ) {
+ __GLX_BEGIN_VARIABLE( rop, cmdlen );
+ __GLX_PUT_LONG( 4, target );
+ __GLX_PUT_LONG( 8, level );
+ __GLX_PUT_LONG( 12, xoffset );
+ __GLX_PUT_LONG( 16, yoffset );
+ __GLX_PUT_LONG( 20, width );
+ __GLX_PUT_LONG( 24, height );
+ __GLX_PUT_LONG( 28, format );
+ __GLX_PUT_LONG( 32, image_size );
+ if ( compsize != 0 ) {
+ __GLX_PUT_CHAR_ARRAY( __GLX_COMPRESSED_TEXSUBIMAGE_CMD_HDR_SIZE,
+ data, image_size );
+ }
+ __GLX_END( cmdlen );
+ }
+ else {
+ assert( compsize != 0 );
+
+ __GLX_BEGIN_VARIABLE_LARGE( rop, cmdlen + 4 );
+ __GLX_PUT_LONG( 8, target );
+ __GLX_PUT_LONG( 12, level );
+ __GLX_PUT_LONG( 16, xoffset );
+ __GLX_PUT_LONG( 20, yoffset );
+ __GLX_PUT_LONG( 24, width );
+ __GLX_PUT_LONG( 28, height );
+ __GLX_PUT_LONG( 32, format );
+ __GLX_PUT_LONG( 36, image_size );
+ __glXSendLargeCommand( gc, gc->pc,
+ __GLX_COMPRESSED_TEXSUBIMAGE_CMD_HDR_SIZE + 4,
+ data, image_size );
+ }
+}
+
+
+void
+__indirect_glCompressedTexImage1DARB( GLenum target, GLint level,
+ GLenum internal_format, GLsizei width,
+ GLint border, GLsizei image_size,
+ const GLvoid *data )
+{
+ CompressedTexImage1D2D( target, level, internal_format, width, 0,
+ border, image_size, data,
+ X_GLrop_CompressedTexImage1D );
+}
+
+
+void
+__indirect_glCompressedTexImage2DARB( GLenum target, GLint level,
+ GLenum internal_format,
+ GLsizei width, GLsizei height,
+ GLint border, GLsizei image_size,
+ const GLvoid *data )
+{
+ CompressedTexImage1D2D( target, level, internal_format, width, height,
+ border, image_size, data,
+ X_GLrop_CompressedTexImage2D );
+}
+
+
+void
+__indirect_glCompressedTexImage3DARB( GLenum target, GLint level,
+ GLenum internal_format,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLsizei image_size,
+ const GLvoid *data )
+{
+ __GLX_DECLARE_VARIABLES();
+
+ __GLX_LOAD_VARIABLES();
+ if ( gc->currentDpy == NULL ) {
+ return;
+ }
+
+ cmdlen = __GLX_PAD( __GLX_COMPRESSED_TEXIMAGE_3D_CMD_HDR_SIZE
+ + image_size );
+ if ( cmdlen <= gc->maxSmallRenderCommandSize ) {
+ __GLX_BEGIN_VARIABLE( X_GLrop_CompressedTexImage3D, cmdlen );
+ __GLX_PUT_LONG( 4, target );
+ __GLX_PUT_LONG( 8, level );
+ __GLX_PUT_LONG( 12, internal_format );
+ __GLX_PUT_LONG( 16, width );
+ __GLX_PUT_LONG( 20, height );
+ __GLX_PUT_LONG( 24, depth );
+ __GLX_PUT_LONG( 28, border );
+ __GLX_PUT_LONG( 32, image_size );
+ if ( image_size != 0 ) {
+ __GLX_PUT_CHAR_ARRAY( __GLX_COMPRESSED_TEXIMAGE_3D_CMD_HDR_SIZE,
+ data, image_size );
+ }
+ __GLX_END( cmdlen );
+ }
+ else {
+ __GLX_BEGIN_VARIABLE_LARGE( X_GLrop_CompressedTexImage3D,
+ cmdlen + 4 );
+ __GLX_PUT_LONG( 8, target );
+ __GLX_PUT_LONG( 12, level );
+ __GLX_PUT_LONG( 16, internal_format );
+ __GLX_PUT_LONG( 20, width );
+ __GLX_PUT_LONG( 24, height );
+ __GLX_PUT_LONG( 28, depth );
+ __GLX_PUT_LONG( 32, border );
+ __GLX_PUT_LONG( 36, image_size );
+ __glXSendLargeCommand( gc, gc->pc,
+ __GLX_COMPRESSED_TEXIMAGE_3D_CMD_HDR_SIZE + 4,
+ data, image_size );
+ }
+}
+
+
+void
+__indirect_glCompressedTexSubImage1DARB( GLenum target, GLint level,
+ GLint xoffset,
+ GLsizei width,
+ GLenum format, GLsizei image_size,
+ const GLvoid *data )
+{
+ CompressedTexSubImage1D2D( target, level, xoffset, 0, width, 0,
+ format, image_size, data,
+ X_GLrop_CompressedTexSubImage1D );
+}
+
+
+void
+__indirect_glCompressedTexSubImage2DARB( GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLsizei image_size,
+ const GLvoid *data )
+{
+ CompressedTexSubImage1D2D( target, level, xoffset, yoffset, width, height,
+ format, image_size, data,
+ X_GLrop_CompressedTexSubImage2D );
+}
+
+
+void
+__indirect_glCompressedTexSubImage3DARB( GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLsizei image_size,
+ const GLvoid *data )
+{
+ __GLX_DECLARE_VARIABLES();
+
+ __GLX_LOAD_VARIABLES();
+ if ( gc->currentDpy == NULL ) {
+ return;
+ }
+
+ cmdlen = __GLX_PAD( __GLX_COMPRESSED_TEXSUBIMAGE_3D_CMD_HDR_SIZE
+ + image_size );
+ if ( cmdlen <= gc->maxSmallRenderCommandSize ) {
+ __GLX_BEGIN_VARIABLE( X_GLrop_CompressedTexSubImage3D, cmdlen );
+ __GLX_PUT_LONG( 4, target );
+ __GLX_PUT_LONG( 8, level );
+ __GLX_PUT_LONG( 12, xoffset );
+ __GLX_PUT_LONG( 16, yoffset );
+ __GLX_PUT_LONG( 20, zoffset );
+ __GLX_PUT_LONG( 24, width );
+ __GLX_PUT_LONG( 28, height );
+ __GLX_PUT_LONG( 32, depth );
+ __GLX_PUT_LONG( 36, format );
+ __GLX_PUT_LONG( 40, image_size );
+ if ( image_size != 0 ) {
+ __GLX_PUT_CHAR_ARRAY( __GLX_COMPRESSED_TEXSUBIMAGE_3D_CMD_HDR_SIZE,
+ data, image_size );
+ }
+ __GLX_END( cmdlen );
+ }
+ else {
+ __GLX_BEGIN_VARIABLE_LARGE( X_GLrop_CompressedTexSubImage3D,
+ cmdlen + 4 );
+ __GLX_PUT_LONG( 8, target );
+ __GLX_PUT_LONG( 12, level );
+ __GLX_PUT_LONG( 16, xoffset );
+ __GLX_PUT_LONG( 20, yoffset );
+ __GLX_PUT_LONG( 24, zoffset );
+ __GLX_PUT_LONG( 28, width );
+ __GLX_PUT_LONG( 32, height );
+ __GLX_PUT_LONG( 36, depth );
+ __GLX_PUT_LONG( 40, format );
+ __GLX_PUT_LONG( 44, image_size );
+ __glXSendLargeCommand( gc, gc->pc,
+ __GLX_COMPRESSED_TEXSUBIMAGE_3D_CMD_HDR_SIZE + 4,
+ data, image_size );
+ }
+}
diff --git a/src/glx/x11/indirect_vertex_array_priv.h b/src/glx/x11/indirect_vertex_array_priv.h
new file mode 100644
index 0000000000..ab97dc645f
--- /dev/null
+++ b/src/glx/x11/indirect_vertex_array_priv.h
@@ -0,0 +1,308 @@
+/*
+ * (C) Copyright IBM Corporation 2004, 2005
+ * 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
+ * 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.
+ */
+
+#ifndef _INDIRECT_VA_PRIVATE_
+#define _INDIRECT_VA_PRIVATE_
+
+/**
+ * \file indirect_va_private.h
+ *
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+#include <inttypes.h>
+
+#include "glxclient.h"
+#include "indirect.h"
+#include <GL/glxproto.h>
+
+
+/**
+ * State descriptor for a single array of vertex data.
+ */
+struct array_state {
+ /**
+ * Pointer to the application supplied data.
+ */
+ const void * data;
+
+ /**
+ * Enum representing the type of the application supplied data.
+ */
+ GLenum data_type;
+
+ /**
+ * Stride value supplied by the application. This value is not used
+ * internally. It is only kept so that it can be queried by the
+ * application using glGet*v.
+ */
+ GLsizei user_stride;
+
+ /**
+ * Calculated size, in bytes, of a single element in the array. This
+ * is calculated based on \c count and the size of the data type
+ * represented by \c data_type.
+ */
+ GLsizei element_size;
+
+ /**
+ * Actual byte-stride from one element to the next. This value will
+ * be equal to either \c user_stride or \c element_stride.
+ */
+ GLsizei true_stride;
+
+ /**
+ * Number of data values in each element.
+ */
+ GLint count;
+
+ /**
+ * "Normalized" data is on the range [0,1] (unsigned) or [-1,1] (signed).
+ * This is used for mapping integral types to floating point types.
+ */
+ GLboolean normalized;
+
+ /**
+ * Pre-calculated GLX protocol command header.
+ */
+ uint32_t header[2];
+
+ /**
+ * Size of the header data. For simple data, like glColorPointerfv,
+ * this is 4. For complex data that requires either a count (e.g.,
+ * glWeightfvARB), an index (e.g., glVertexAttrib1fvARB), or a
+ * selector enum (e.g., glMultiTexCoord2fv) this is 8.
+ */
+ unsigned header_size;
+
+ /**
+ * Set to \c GL_TRUE if this array is enabled. Otherwise, it is set
+ * to \c GL_FALSE.
+ */
+ GLboolean enabled;
+
+ /**
+ * For multi-arrayed data (e.g., texture coordinates, generic vertex
+ * program attributes, etc.), this specifies which array this is.
+ */
+ unsigned index;
+
+ /**
+ * Per-array-type key. For most arrays, this will be the GL enum for
+ * that array (e.g., GL_VERTEX_ARRAY for vertex data, GL_NORMAL_ARRAY
+ * for normal data, GL_TEXTURE_COORD_ARRAY for texture coordinate data,
+ * etc.).
+ */
+ GLenum key;
+
+ /**
+ * If this array can be used with the "classic" \c glDrawArrays protocol,
+ * this is set to \c GL_TRUE. Otherwise, it is set to \c GL_FALSE.
+ */
+ GLboolean old_DrawArrays_possible;
+};
+
+
+/**
+ * Array state that is pushed / poped by \c glPushClientAttrib and
+ * \c glPopClientAttrib.
+ */
+struct array_stack_state {
+ /**
+ * Pointer to the application supplied data.
+ */
+ const void * data;
+
+ /**
+ * Enum representing the type of the application supplied data.
+ */
+ GLenum data_type;
+
+ /**
+ * Stride value supplied by the application. This value is not used
+ * internally. It is only kept so that it can be queried by the
+ * application using glGet*v.
+ */
+ GLsizei user_stride;
+
+ /**
+ * Number of data values in each element.
+ */
+ GLint count;
+
+ /**
+ * Per-array-type key. For most arrays, this will be the GL enum for
+ * that array (e.g., GL_VERTEX_ARRAY for vertex data, GL_NORMAL_ARRAY
+ * for normal data, GL_TEXTURE_COORD_ARRAY for texture coordinate data,
+ * etc.).
+ */
+ GLenum key;
+
+ /**
+ * For multi-arrayed data (e.g., texture coordinates, generic vertex
+ * program attributes, etc.), this specifies which array this is.
+ */
+ unsigned index;
+
+ /**
+ * Set to \c GL_TRUE if this array is enabled. Otherwise, it is set
+ * to \c GL_FALSE.
+ */
+ GLboolean enabled;
+};
+
+
+/**
+ * Collection of all the vertex array state.
+ */
+struct array_state_vector {
+ /**
+ * Number of arrays tracked by \c ::arrays.
+ */
+ size_t num_arrays;
+
+ /**
+ * Array of vertex array state. This array contains all of the valid
+ * vertex arrays. If a vertex array isn't in this array, then it isn't
+ * valid. For example, if an implementation does not support
+ * EXT_fog_coord, there won't be a GL_FOG_COORD_ARRAY entry in this
+ * array.
+ */
+ struct array_state * arrays;
+
+ /**
+ * Number of currently enabled client-side arrays. The value of this
+ * field is only valid if \c array_info_cache_valid is true.
+ */
+ size_t enabled_client_array_count;
+
+ /**
+ * \name ARRAY_INFO cache.
+ *
+ * These fields track the state of the ARRAY_INFO cache. The
+ * \c array_info_cache_size is the size of the actual data stored in
+ * \c array_info_cache. \c array_info_cache_buffer_size is the size of
+ * the buffer. This will always be greater than or equal to
+ * \c array_info_cache_size.
+ *
+ * \note
+ * There are some bytes of extra data before \c array_info_cache that is
+ * used to hold the header for RenderLarge commands. This is
+ * \b not included in \c array_info_cache_size or
+ * \c array_info_cache_buffer_size. \c array_info_cache_base stores a
+ * pointer to the true start of the buffer (i.e., what malloc returned).
+ */
+ /*@{*/
+ size_t array_info_cache_size;
+ size_t array_info_cache_buffer_size;
+ void * array_info_cache;
+ void * array_info_cache_base;
+ /*@}*/
+
+
+ /**
+ * Is the cache of ARRAY_INFO data valid? The cache can become invalid
+ * when one of several state changes occur. Among these chages are
+ * modifying the array settings for an enabled array and enabling /
+ * disabling an array.
+ */
+ GLboolean array_info_cache_valid;
+
+ /**
+ * Is it possible to use the GL 1.1 / EXT_vertex_arrays protocol? Use
+ * of this protocol is disabled with really old servers (i.e., servers
+ * that don't support GL 1.1 or EXT_vertex_arrays) or when an environment
+ * variable is set.
+ *
+ * \todo
+ * GL 1.1 and EXT_vertex_arrays use identical protocol, but have different
+ * opcodes for \c glDrawArrays. For servers that advertise one or the
+ * other, there should be a way to select which opcode to use.
+ */
+ GLboolean old_DrawArrays_possible;
+
+ /**
+ * Is it possible to use the new GL X.X / ARB_vertex_buffer_object
+ * protocol?
+ *
+ * \todo
+ * This protocol has not yet been defined by the ARB, but is currently a
+ * work in progress. This field is a place-holder.
+ */
+ GLboolean new_DrawArrays_possible;
+
+ /**
+ * Active texture unit set by \c glClientActiveTexture.
+ *
+ * \sa __glXGetActiveTextureUnit
+ */
+ unsigned active_texture_unit;
+
+ /**
+ * Number of supported texture units. Even if ARB_multitexture /
+ * GL 1.3 are not supported, this will be at least 1. When multitexture
+ * is supported, this will be the value queried by calling
+ * \c glGetIntegerv with \c GL_MAX_TEXTURE_UNITS.
+ *
+ * \todo
+ * Investigate if this should be the value of \c GL_MAX_TEXTURE_COORDS
+ * instead (if GL 2.0 / ARB_fragment_shader / ARB_fragment_program /
+ * NV_fragment_program are supported).
+ */
+ unsigned num_texture_units;
+
+ /**
+ * Number of generic vertex program attribs. If GL_ARB_vertex_program
+ * is not supported, this will be zero. Otherwise it will be the value
+ * queries by calling \c glGetProgramiv with \c GL_VERTEX_PROGRAM_ARB
+ * and \c GL_MAX_PROGRAM_ATTRIBS_ARB.
+ */
+ unsigned num_vertex_program_attribs;
+
+ /**
+ * \n Methods for implementing various GL functions.
+ *
+ * These method pointers are only valid \c array_info_cache_valid is set.
+ * When each function starts, it much check \c array_info_cache_valid.
+ * If it is not set, it must call \c fill_array_info_cache and call
+ * the new method.
+ *
+ * \sa fill_array_info_cache
+ *
+ * \todo
+ * Write code to plug these functions directly into the dispatch table.
+ */
+ /*@{*/
+ void (*DrawArrays)( GLenum, GLint, GLsizei );
+ void (*DrawElements)( GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices );
+ /*@}*/
+
+ struct array_stack_state * stack;
+ unsigned active_texture_unit_stack[ __GL_CLIENT_ATTRIB_STACK_DEPTH ];
+ unsigned stack_index;
+};
+
+#endif /* _INDIRECT_VA_PRIVATE_ */