add missed files for DRI2 merge

This commit is contained in:
Alan Hourihane 2008-06-11 15:25:35 +01:00
parent 1bcb817167
commit 5e9fe62c70
11 changed files with 2866 additions and 0 deletions

View file

@ -0,0 +1,134 @@
/*
* Copyright 2007 Red Hat, 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
* 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.
*/
#ifndef DRI_SAREA_H
#define DRI_SAREA_H
#include <drm.h>
/* The DRI2 SAREA holds a list of self-describing blocks. Each block
* is 8 byte aligned and has a common 32-bit header word. The upper
* 16 bits describe the type of the block and the lower 16 bits the
* size. DRI2 only defines a couple of blocks and allows drivers to
* define driver specific blocks using type codes from 0x8000 and up.
* The type code 0x0000 defines the end of the sarea. */
#define DRI2_SAREA_BLOCK_HEADER(type, size) (((type) << 16) | (size))
#define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16)
#define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff)
#define DRI2_SAREA_BLOCK_NEXT(p) \
((void *) ((unsigned char *) (p) + \
DRI2_SAREA_BLOCK_SIZE(*(unsigned int *) p)))
#define DRI2_SAREA_BLOCK_END 0x0000
#define DRI2_SAREA_BLOCK_LOCK 0x0001
#define DRI2_SAREA_BLOCK_EVENT_BUFFER 0x0002
/* Chipset specific blocks start at 0x8000, 0xffff is reserved. */
typedef struct __DRILock __DRILock;
typedef struct __DRIEventBuffer __DRIEventBuffer;
typedef struct __DRIDrawableBuffer __DRIDrawableBuffer;
typedef struct __DRIDrawableConfigEvent __DRIDrawableConfigEvent;
typedef struct __DRIBufferAttachEvent __DRIBufferAttachEvent;
struct __DRILock {
unsigned int block_header;
drm_hw_lock_t lock;
/* We use this with DRM_CAS to allocate lock IDs for the real lock.*/
unsigned int next_id;
};
struct __DRIEventBuffer {
unsigned int block_header;
unsigned int head; /* last valid event */
unsigned int prealloc; /* event currently being written */
unsigned int size; /* size of data */
unsigned char data[0];
};
enum {
/* the four standard color buffers */
DRI_DRAWABLE_BUFFER_FRONT_LEFT = 0,
DRI_DRAWABLE_BUFFER_BACK_LEFT = 1,
DRI_DRAWABLE_BUFFER_FRONT_RIGHT = 2,
DRI_DRAWABLE_BUFFER_BACK_RIGHT = 3,
/* optional aux buffer */
DRI_DRAWABLE_BUFFER_AUX0 = 4,
DRI_DRAWABLE_BUFFER_AUX1 = 5,
DRI_DRAWABLE_BUFFER_AUX2 = 6,
DRI_DRAWABLE_BUFFER_AUX3 = 7,
DRI_DRAWABLE_BUFFER_DEPTH = 8,
DRI_DRAWABLE_BUFFER_STENCIL = 9,
DRI_DRAWABLE_BUFFER_ACCUM = 10,
/* generic renderbuffers */
DRI_DRAWABLE_BUFFER_COLOR0 = 11,
DRI_DRAWABLE_BUFFER_COLOR1 = 12,
DRI_DRAWABLE_BUFFER_COLOR2 = 13,
DRI_DRAWABLE_BUFFER_COLOR3 = 14,
DRI_DRAWABLE_BUFFER_COLOR4 = 15,
DRI_DRAWABLE_BUFFER_COLOR5 = 16,
DRI_DRAWABLE_BUFFER_COLOR6 = 17,
DRI_DRAWABLE_BUFFER_COLOR7 = 18,
DRI_DRAWABLE_BUFFER_COUNT = 19
};
struct __DRIDrawableBuffer {
unsigned int attachment;
unsigned int handle;
unsigned int pitch;
unsigned short cpp;
/* Upper 8 bits are driver specific, lower 8 bits generic. The
* bits can inidicate buffer properties such as tiled, swizzled etc. */
unsigned short flags;
};
#define DRI2_EVENT_HEADER(type, size) (((type) << 16) | (size))
#define DRI2_EVENT_TYPE(b) ((b) >> 16)
#define DRI2_EVENT_SIZE(b) ((b) & 0xffff)
#define DRI2_EVENT_PAD 0x0000
#define DRI2_EVENT_DRAWABLE_CONFIG 0x0001
#define DRI2_EVENT_BUFFER_ATTACH 0x0002
struct __DRIDrawableConfigEvent {
unsigned int event_header;
unsigned int drawable;
short x;
short y;
unsigned int width;
unsigned int height;
unsigned int num_rects;
struct drm_clip_rect rects[0];
};
struct __DRIBufferAttachEvent {
unsigned int event_header;
unsigned int drawable;
__DRIDrawableBuffer buffer;
};
#endif /* DRI_SAREA_H */

252
src/glx/x11/dri2.c Normal file
View file

@ -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;
}

53
src/glx/x11/dri2.h Normal file
View file

@ -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

371
src/glx/x11/dri2_glx.c Normal file
View file

@ -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 */

399
src/glx/x11/dri_common.c Normal file
View file

@ -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 */

60
src/glx/x11/dri_common.h Normal file
View file

@ -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 */

510
src/glx/x11/glxcurrent.c Normal file
View file

@ -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)

416
src/glx/x11/glxhash.c Normal file
View file

@ -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

16
src/glx/x11/glxhash.h Normal file
View file

@ -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_ */

View file

@ -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 );
}
}

View file

@ -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_ */