use FetchTexelf() in GetTexImage() to return float textures correctly
[mesa.git] / src / mesa / glapi / glapi.c
index d50a37bd9ffbfbfc13ffed388ea6dc24ca028a20..eff86f42bef99da51d8d38c5357577da6973a733 100644 (file)
@@ -1,4 +1,3 @@
-/* $Id: glapi.c,v 1.62 2002/05/29 15:23:16 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
  * 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
@@ -101,7 +121,7 @@ warn(void)
 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;
 }
@@ -170,12 +190,10 @@ struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_
 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.
  */
@@ -421,31 +439,6 @@ _glapi_get_override_dispatch(int layer)
 }
 
 
-
-/*
- * 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 */
-}
-
-
 struct name_address_offset {
    const char *Name;
    GLvoid *Address;
@@ -453,7 +446,7 @@ struct name_address_offset {
 };
 
 
-/* The code in this file is auto-generated */
+/* The code in this file is auto-generated with Python */
 #include "glprocs.h"
 
 
@@ -497,8 +490,20 @@ get_static_proc_address(const char *funcName)
  * 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;
@@ -532,7 +537,7 @@ generate_entrypoint(GLuint functionOffset)
     * 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,
@@ -540,10 +545,10 @@ generate_entrypoint(GLuint functionOffset)
       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;
@@ -554,7 +559,7 @@ generate_entrypoint(GLuint functionOffset)
    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       */
@@ -577,12 +582,12 @@ generate_entrypoint(GLuint functionOffset)
           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]);
@@ -603,10 +608,42 @@ generate_entrypoint(GLuint functionOffset)
    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.
@@ -615,6 +652,10 @@ generate_entrypoint(GLuint functionOffset)
 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);
@@ -623,103 +664,56 @@ _glapi_add_entrypoint(const char *funcName, GLuint offset)
       }
    }
 
+   /* 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.
  */
@@ -746,8 +740,12 @@ _glapi_get_proc_offset(const char *funcName)
 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;
@@ -755,9 +753,35 @@ _glapi_get_proc_address(const char *funcName)
    }
 
    /* 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;
+   }
+}
 
 
 
@@ -770,6 +794,8 @@ _glapi_get_proc_name(GLuint offset)
 {
    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;
@@ -786,6 +812,29 @@ _glapi_get_proc_name(GLuint offset)
 
 
 
+/*
+ * 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.
  * Intended for debugging purposes.
@@ -862,5 +911,13 @@ _glapi_check_table(const struct _glapi_table *table)
       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
 }