-/* $Id: glapi.c,v 1.59 2001/11/18 22:48:11 brianp Exp $ */
/*
* Mesa 3-D graphics library
- * Version: 3.5
+ * Version: 4.1
*
- * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2002 Brian Paul 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"),
* flexible enough to be reused in several places: XFree86, DRI-
* based libGL.so, and perhaps the SGI SI.
*
- * There are no dependencies on Mesa in this code.
+ * NOTE: There are no dependencies on Mesa in this code.
*
* Versions (API changes):
* 2000/02/23 - original version for Mesa 3.3 and XFree86 4.0
* 2001/01/16 - added dispatch override feature for Mesa 3.5
+ * 2002/06/28 - added _glapi_set_warning_func(), Mesa 4.1.
+ * 2002/10/01 - _glapi_get_proc_address() will now generate new entrypoints
+ * itself (using offset ~0). _glapi_add_entrypoint() can be
+ * called afterward and it'll fill in the correct dispatch
+ * offset. This allows DRI libGL to avoid probing for DRI
+ * drivers! No changes to the public glapi interface.
*/
/***** BEGIN NO-OP DISPATCH *****/
static GLboolean WarnFlag = GL_FALSE;
+static _glapi_warning_func warning_func;
+
+/*
+ * Enable/disable printing of warning messages.
+ */
void
_glapi_noop_enable_warnings(GLboolean enable)
{
WarnFlag = enable;
}
+/*
+ * Register a callback function for reporting errors.
+ */
+void
+_glapi_set_warning_func( _glapi_warning_func func )
+{
+ warning_func = func;
+}
+
static GLboolean
warn(void)
{
- if (WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
+ if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
+ && warning_func) {
return GL_TRUE;
- else
+ }
+ else {
return GL_FALSE;
+ }
}
#define KEYWORD1 static
-#define KEYWORD2
+#define KEYWORD2 GLAPIENTRY
#define NAME(func) NoOp##func
-#define F stderr
+#define F NULL
-#define DISPATCH(func, args, msg) \
- if (warn()) { \
- fprintf(stderr, "GL User Error: calling "); \
- fprintf msg; \
- fprintf(stderr, " without a current context\n"); \
+#define DISPATCH(func, args, msg) \
+ if (warn()) { \
+ warning_func(NULL, "GL User Error: called without context:"); \
+ warning_func msg; \
}
-#define RETURN_DISPATCH(func, args, msg) \
- if (warn()) { \
- fprintf(stderr, "GL User Error: calling "); \
- fprintf msg; \
- fprintf(stderr, " without a current context\n"); \
- } \
+#define RETURN_DISPATCH(func, args, msg) \
+ if (warn()) { \
+ warning_func(NULL, "GL User Error: called without context:"); \
+ warning_func msg; \
+ } \
return 0
#define DISPATCH_TABLE_NAME __glapi_noop_table
static int NoOpUnused(void)
{
if (warn()) {
- fprintf(stderr, "GL User Error: calling extension function without a current context\n");
+ warning_func(NULL, "GL User Error: calling extension function without a current context\n");
}
return 0;
}
void *_glapi_Context = NULL;
-static GLuint MaxDispatchOffset = sizeof(struct _glapi_table) / sizeof(void *) - 1;
-static GLboolean GetSizeCalled = GL_FALSE;
-
static GLboolean DispatchOverride = GL_FALSE;
+
/* strdup() is actually not a standard ANSI C or POSIX routine.
* Irix will not define it if ANSI mode is in effect.
*/
/*
* We should call this periodically from a function such as glXMakeCurrent
- * in order to test if multiple threads are being used. When we detect
- * that situation we should then call _glapi_enable_thread_safety()
+ * in order to test if multiple threads are being used.
*/
void
_glapi_check_multithread(void)
}
-
-/*
- * Return size of dispatch table struct as number of functions (or
- * slots).
- */
-GLuint
-_glapi_get_dispatch_table_size(void)
-{
- /* return sizeof(struct _glapi_table) / sizeof(void *);*/
- GetSizeCalled = GL_TRUE;
- return MaxDispatchOffset + 1;
-}
-
-
-
-/*
- * Get API dispatcher version string.
- */
-const char *
-_glapi_get_version(void)
-{
- return "20010116"; /* YYYYMMDD */
-}
-
-
-/*
- * For each entry in static_functions[] which use this function
- * we should implement a dispatch function in glapitemp.h and
- * in glapinoop.c
- */
-static int NotImplemented(void)
-{
- return 0;
-}
-
-
struct name_address_offset {
const char *Name;
GLvoid *Address;
};
-/* The code in this file is auto-generated */
+/* The code in this file is auto-generated with Python */
#include "glprocs.h"
* Extension function management.
*/
+/*
+ * Number of extension functions which we can dynamically add at runtime.
+ */
+#define MAX_EXTENSION_FUNCS 300
+
+
+/*
+ * The disptach table size (number of entries) is the sizeof the
+ * _glapi_table struct plus the number of dynamic entries we can add.
+ * The extra slots can be filled in by DRI drivers that register new extension
+ * functions.
+ */
+#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
-#define MAX_EXTENSION_FUNCS 1000
static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
static GLuint NumExtEntryPoints = 0;
* 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
* 14 15 16 17 18 19
*/
- static const unsigned char temp[] = {
+ static const unsigned char insn_template[] = {
0xa1, 0x00, 0x00, 0x00, 0x00,
0x85, 0xc0,
0x74, 0x06,
0xe8, 0x00, 0x00, 0x00, 0x00,
0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
};
- unsigned char *code = malloc(sizeof(temp));
+ unsigned char *code = (unsigned char *) malloc(sizeof(insn_template));
unsigned int next_insn;
if (code) {
- memcpy(code, temp, sizeof(temp));
+ memcpy(code, insn_template, sizeof(insn_template));
*(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
*(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
return code;
#elif defined(USE_SPARC_ASM)
-#ifdef __sparc_v9__
+#if defined(__sparc_v9__) && !defined(__linux__)
static const unsigned int insn_template[] = {
0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
0x01000000 /* nop */
};
#endif
- unsigned int *code = malloc(sizeof(insn_template));
+ unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
if (code) {
memcpy(code, insn_template, sizeof(insn_template));
-#ifdef __sparc_v9__
+#if defined(__sparc_v9__) && !defined(__linux__)
code[0] |= (glapi_addr >> (32 + 10));
code[1] |= ((glapi_addr & 0xffffffff) >> 10);
__glapi_sparc_icache_flush(&code[0]);
return code;
#else
return NULL;
-#endif
+#endif /* USE_*_ASM */
}
+/*
+ * This function inserts a new dispatch offset into the assembly language
+ * stub that was generated with the preceeding function.
+ */
+static void
+fill_in_entrypoint_offset(void *entrypoint, GLuint offset)
+{
+#if defined(USE_X86_ASM)
+
+ unsigned char *code = (unsigned char *) entrypoint;
+ *(unsigned int *)(code + 0x0b) = offset * 4;
+ *(unsigned int *)(code + 0x16) = offset * 4;
+
+#elif defined(USE_SPARC_ASM)
+
+ /* XXX this hasn't been tested! */
+ unsigned int *code = (unsigned int *) entrypoint;
+#if defined(__sparc_v9__) && !defined(__linux__)
+ code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
+ code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
+ code[6] |= ((offset * 8) >> 10);
+ code[7] |= ((offset * 8) & ((1 << 10) - 1));
+ __glapi_sparc_icache_flush(&code[6]);
+#else /* __sparc_v9__ && !linux */
+ code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
+ code[2] |= (offset * 4);
+ __glapi_sparc_icache_flush(&code[2]);
+#endif /* __sparc_v9__ && !linux */
+
+#endif /* USE_*_ASM */
+}
+
/*
* Add a new extension function entrypoint.
GLboolean
_glapi_add_entrypoint(const char *funcName, GLuint offset)
{
+ /* trivial rejection test */
+ if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
+ return GL_FALSE;
+
/* first check if the named function is already statically present */
{
GLint index = get_static_proc_offset(funcName);
}
}
+ /* See if this function has already been dynamically added */
{
- /* make sure this offset/name pair is legal */
- const char *name = _glapi_get_proc_name(offset);
- if (name && strcmp(name, funcName) != 0)
- return GL_FALSE; /* bad name! */
- }
-
- {
- /* be sure index and name match known data */
GLuint i;
for (i = 0; i < NumExtEntryPoints; i++) {
if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
- /* function already registered with api */
+ /* function already registered */
if (ExtEntryTable[i].Offset == offset) {
return GL_TRUE; /* offsets match */
}
+ else if (ExtEntryTable[i].Offset == (GLuint) ~0
+ && offset < DISPATCH_TABLE_SIZE) {
+ /* need to patch-up the dispatch code */
+ if (offset != (GLuint) ~0) {
+ fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
+ ExtEntryTable[i].Offset = offset;
+ }
+ return GL_TRUE;
+ }
else {
return GL_FALSE; /* bad offset! */
}
}
}
+ }
- /* Make sure we don't try to add a new entrypoint after someone
- * has already called _glapi_get_dispatch_table_size()! If that's
- * happened the caller's information would become out of date.
- */
- if (GetSizeCalled)
- return GL_FALSE;
-
- /* make sure we have space */
- if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS) {
- return GL_FALSE;
- }
- else {
- void *entrypoint = generate_entrypoint(offset);
- if (!entrypoint)
- return GL_FALSE;
-
- ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
- ExtEntryTable[NumExtEntryPoints].Offset = offset;
- ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
- NumExtEntryPoints++;
+ /* This is a new function, try to add it. */
+ if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
+ offset >= DISPATCH_TABLE_SIZE) {
+ /* No space left */
+ return GL_FALSE;
+ }
+ else {
+ void *entrypoint = generate_entrypoint(offset);
+ if (!entrypoint)
+ return GL_FALSE; /* couldn't generate assembly */
- if (offset > MaxDispatchOffset)
- MaxDispatchOffset = offset;
+ /* OK! */
+ ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
+ ExtEntryTable[NumExtEntryPoints].Offset = offset;
+ ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
+ NumExtEntryPoints++;
- return GL_TRUE; /* success */
- }
+ return GL_TRUE; /* success */
}
- /* should never get here, but play it safe */
+ /* should never get here, silence compiler warnings */
return GL_FALSE;
}
-
-#if 0000 /* prototype code for dynamic extension slot allocation */
-
-static int NextFreeOffset = 409; /*XXX*/
-#define MAX_DISPATCH_TABLE_SIZE 1000
-
-/*
- * Dynamically allocate a dispatch slot for an extension entrypoint
- * and generate the assembly language dispatch stub.
- * Return the dispatch offset for the function or -1 if no room or error.
- */
-GLint
-_glapi_add_entrypoint2(const char *funcName)
-{
- int offset;
-
- /* first see if extension func is already known */
- offset = _glapi_get_proc_offset(funcName);
- if (offset >= 0)
- return offset;
-
- if (NumExtEntryPoints < MAX_EXTENSION_FUNCS
- && NextFreeOffset < MAX_DISPATCH_TABLE_SIZE) {
- void *entryPoint;
- offset = NextFreeOffset;
- entryPoint = generate_entrypoint(offset);
- if (entryPoint) {
- NextFreeOffset++;
- ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
- ExtEntryTable[NumExtEntryPoints].Offset = offset;
- ExtEntryTable[NumExtEntryPoints].Address = entryPoint;
- NumExtEntryPoints++;
- return offset;
- }
- }
- return -1;
-}
-
-#endif
-
-
-
/*
* Return offset of entrypoint for named function within dispatch table.
*/
const GLvoid *
_glapi_get_proc_address(const char *funcName)
{
- /* search extension functions first */
GLuint i;
+
+ if (funcName[0] != 'g' || funcName[1] != 'l')
+ return NULL;
+
+ /* search extension functions first */
for (i = 0; i < NumExtEntryPoints; i++) {
if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
return ExtEntryTable[i].Address;
}
/* search static functions */
- return get_static_proc_address(funcName);
-}
+ {
+ const GLvoid *func = get_static_proc_address(funcName);
+ if (func)
+ return func;
+ }
+
+ /* generate new entrypoint - use a temporary dispatch offset of
+ * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
+ * we'll put in the proper offset. If that never happens, and the
+ * user calls this function, he'll segfault. That's what you get
+ * when you try calling a GL function that doesn't really exist.
+ */
+ if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
+ GLvoid *entrypoint = generate_entrypoint(~0);
+ if (!entrypoint)
+ return GL_FALSE;
+ ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
+ ExtEntryTable[NumExtEntryPoints].Offset = ~0;
+ ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
+ NumExtEntryPoints++;
+
+ return entrypoint;
+ }
+ else {
+ /* no space for new functions! */
+ return NULL;
+ }
+}
{
const GLuint n = sizeof(static_functions) / sizeof(struct name_address_offset);
GLuint i;
+
+ /* search built-in functions */
for (i = 0; i < n; i++) {
if (static_functions[i].Offset == offset)
return static_functions[i].Name;
+/*
+ * Return size of dispatch table struct as number of functions (or
+ * slots).
+ */
+GLuint
+_glapi_get_dispatch_table_size(void)
+{
+ return DISPATCH_TABLE_SIZE;
+}
+
+
+
+/*
+ * Get API dispatcher version string.
+ */
+const char *
+_glapi_get_version(void)
+{
+ return "20021001"; /* YYYYMMDD */
+}
+
+
+
/*
* Make sure there are no NULL pointers in the given dispatch table.
- * Intented for debugging purposes.
+ * Intended for debugging purposes.
*/
void
_glapi_check_table(const struct _glapi_table *table)
{
+#ifdef DEBUG
const GLuint entries = _glapi_get_dispatch_table_size();
const void **tab = (const void **) table;
GLuint i;
assert(tab[i]);
}
-#ifdef DEBUG
/* Do some spot checks to be sure that the dispatch table
* slots are assigned correctly.
*/
assert(secondaryColor3fOffset == offset);
assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
}
+ {
+ GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
+ char *pointParameterivFunc = (char*) &table->PointParameterivNV;
+ GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
+ assert(pointParameterivOffset == _gloffset_PointParameterivNV);
+ assert(pointParameterivOffset == offset);
+ assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
+ }
+ {
+ GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
+ char *setFenceFunc = (char*) &table->SetFenceNV;
+ GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
+ assert(setFenceOffset == _gloffset_SetFenceNV);
+ assert(setFenceOffset == offset);
+ assert(_glapi_get_proc_address("glSetFenceNV") == (void *) &glSetFenceNV);
+ }
#endif
}