1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg/**
26848b8605Smrg * \file glapi_getproc.c
27848b8605Smrg *
28848b8605Smrg * Code for implementing glXGetProcAddress(), etc.
29848b8605Smrg * This was originally in glapi.c but refactored out.
30848b8605Smrg */
31848b8605Smrg
32848b8605Smrg
33b8e80941Smrg#include <assert.h>
34b8e80941Smrg#include <string.h>
35b8e80941Smrg#include <stdlib.h>
36848b8605Smrg#include "glapi/glapi_priv.h"
37b8e80941Smrg#include "glapitable.h"
38848b8605Smrg
39848b8605Smrg
40848b8605Smrg#define FIRST_DYNAMIC_OFFSET (sizeof(struct _glapi_table) / sizeof(void *))
41848b8605Smrg
42848b8605Smrg
43b8e80941Smrg
44848b8605Smrg/**********************************************************************
45848b8605Smrg * Static function management.
46848b8605Smrg */
47848b8605Smrg
48848b8605Smrg
49848b8605Smrg#if !defined(DISPATCH_FUNCTION_SIZE)
50848b8605Smrg# define NEED_FUNCTION_POINTER
51848b8605Smrg#endif
52b8e80941Smrg#include "glprocs.h"
53848b8605Smrg
54848b8605Smrg
55848b8605Smrg/**
56848b8605Smrg * Search the table of static entrypoint functions for the named function
57848b8605Smrg * and return the corresponding glprocs_table_t entry.
58848b8605Smrg */
59848b8605Smrgstatic const glprocs_table_t *
60848b8605Smrgget_static_proc( const char * n )
61848b8605Smrg{
62848b8605Smrg   GLuint i;
63848b8605Smrg   for (i = 0; static_functions[i].Name_offset >= 0; i++) {
64848b8605Smrg      const char *testName = gl_string_table + static_functions[i].Name_offset;
65848b8605Smrg      if (strcmp(testName, n) == 0)
66848b8605Smrg      {
67848b8605Smrg	 return &static_functions[i];
68848b8605Smrg      }
69848b8605Smrg   }
70848b8605Smrg   return NULL;
71848b8605Smrg}
72848b8605Smrg
73848b8605Smrg
74848b8605Smrg/**
75848b8605Smrg * Return dispatch table offset of the named static (built-in) function.
76848b8605Smrg * Return -1 if function not found.
77848b8605Smrg */
78848b8605Smrgstatic GLint
79848b8605Smrgget_static_proc_offset(const char *funcName)
80848b8605Smrg{
81848b8605Smrg   const glprocs_table_t * const f = get_static_proc( funcName );
82848b8605Smrg   if (f == NULL) {
83848b8605Smrg      return -1;
84848b8605Smrg   }
85848b8605Smrg
86848b8605Smrg   return f->Offset;
87848b8605Smrg}
88848b8605Smrg
89848b8605Smrg
90848b8605Smrg
91848b8605Smrg/**
92848b8605Smrg * Return dispatch function address for the named static (built-in) function.
93848b8605Smrg * Return NULL if function not found.
94848b8605Smrg */
95848b8605Smrgstatic _glapi_proc
96848b8605Smrgget_static_proc_address(const char *funcName)
97848b8605Smrg{
98848b8605Smrg   const glprocs_table_t * const f = get_static_proc( funcName );
99848b8605Smrg   if (f == NULL) {
100848b8605Smrg      return NULL;
101848b8605Smrg   }
102848b8605Smrg
103848b8605Smrg#if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
104848b8605Smrg   return (f->Address == NULL)
105848b8605Smrg      ? get_entrypoint_address(f->Offset)
106848b8605Smrg      : f->Address;
107848b8605Smrg#elif defined(DISPATCH_FUNCTION_SIZE)
108848b8605Smrg   return get_entrypoint_address(f->Offset);
109848b8605Smrg#else
110848b8605Smrg   return f->Address;
111848b8605Smrg#endif
112848b8605Smrg}
113848b8605Smrg
114848b8605Smrg
115848b8605Smrg
116848b8605Smrg/**
117848b8605Smrg * Return the name of the function at the given offset in the dispatch
118848b8605Smrg * table.  For debugging only.
119848b8605Smrg */
120848b8605Smrgstatic const char *
121848b8605Smrgget_static_proc_name( GLuint offset )
122848b8605Smrg{
123848b8605Smrg   GLuint i;
124848b8605Smrg   for (i = 0; static_functions[i].Name_offset >= 0; i++) {
125848b8605Smrg      if (static_functions[i].Offset == offset) {
126848b8605Smrg	 return gl_string_table + static_functions[i].Name_offset;
127848b8605Smrg      }
128848b8605Smrg   }
129848b8605Smrg   return NULL;
130848b8605Smrg}
131848b8605Smrg
132848b8605Smrg
133848b8605Smrg
134848b8605Smrg/**********************************************************************
135848b8605Smrg * Extension function management.
136848b8605Smrg */
137848b8605Smrg
138848b8605Smrg
139848b8605Smrg/**
140848b8605Smrg * Track information about a function added to the GL API.
141848b8605Smrg */
142848b8605Smrgstruct _glapi_function {
143848b8605Smrg   /**
144848b8605Smrg    * Name of the function.
145848b8605Smrg    */
146848b8605Smrg   const char * name;
147848b8605Smrg
148848b8605Smrg
149848b8605Smrg   /**
150848b8605Smrg    * Text string that describes the types of the parameters passed to the
151848b8605Smrg    * named function.   Parameter types are converted to characters using the
152848b8605Smrg    * following rules:
153848b8605Smrg    *   - 'i' for \c GLint, \c GLuint, and \c GLenum
154848b8605Smrg    *   - 'p' for any pointer type
155848b8605Smrg    *   - 'f' for \c GLfloat and \c GLclampf
156848b8605Smrg    *   - 'd' for \c GLdouble and \c GLclampd
157848b8605Smrg    */
158848b8605Smrg   const char * parameter_signature;
159848b8605Smrg
160848b8605Smrg
161848b8605Smrg   /**
162848b8605Smrg    * Offset in the dispatch table where the pointer to the real function is
163848b8605Smrg    * located.  If the driver has not requested that the named function be
164848b8605Smrg    * added to the dispatch table, this will have the value ~0.
165848b8605Smrg    */
166848b8605Smrg   unsigned dispatch_offset;
167848b8605Smrg
168848b8605Smrg
169848b8605Smrg   /**
170848b8605Smrg    * Pointer to the dispatch stub for the named function.
171848b8605Smrg    *
172848b8605Smrg    * \todo
173848b8605Smrg    * The semantic of this field should be changed slightly.  Currently, it
174848b8605Smrg    * is always expected to be non-\c NULL.  However, it would be better to
175848b8605Smrg    * only allocate the entry-point stub when the application requests the
176848b8605Smrg    * function via \c glXGetProcAddress.  This would save memory for all the
177848b8605Smrg    * functions that the driver exports but that the application never wants
178848b8605Smrg    * to call.
179848b8605Smrg    */
180848b8605Smrg   _glapi_proc dispatch_stub;
181848b8605Smrg};
182848b8605Smrg
183848b8605Smrg
184848b8605Smrgstatic struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
185848b8605Smrgstatic GLuint NumExtEntryPoints = 0;
186848b8605Smrg
187848b8605Smrg
188848b8605Smrgstatic struct _glapi_function *
189848b8605Smrgget_extension_proc(const char *funcName)
190848b8605Smrg{
191848b8605Smrg   GLuint i;
192848b8605Smrg   for (i = 0; i < NumExtEntryPoints; i++) {
193848b8605Smrg      if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
194848b8605Smrg         return & ExtEntryTable[i];
195848b8605Smrg      }
196848b8605Smrg   }
197848b8605Smrg   return NULL;
198848b8605Smrg}
199848b8605Smrg
200848b8605Smrg
201848b8605Smrgstatic GLint
202848b8605Smrgget_extension_proc_offset(const char *funcName)
203848b8605Smrg{
204848b8605Smrg   const struct _glapi_function * const f = get_extension_proc( funcName );
205848b8605Smrg   if (f == NULL) {
206848b8605Smrg      return -1;
207848b8605Smrg   }
208848b8605Smrg
209848b8605Smrg   return f->dispatch_offset;
210848b8605Smrg}
211848b8605Smrg
212848b8605Smrg
213848b8605Smrgstatic _glapi_proc
214848b8605Smrgget_extension_proc_address(const char *funcName)
215848b8605Smrg{
216848b8605Smrg   const struct _glapi_function * const f = get_extension_proc( funcName );
217848b8605Smrg   if (f == NULL) {
218848b8605Smrg      return NULL;
219848b8605Smrg   }
220848b8605Smrg
221848b8605Smrg   return f->dispatch_stub;
222848b8605Smrg}
223848b8605Smrg
224848b8605Smrg
225848b8605Smrgstatic const char *
226848b8605Smrgget_extension_proc_name(GLuint offset)
227848b8605Smrg{
228848b8605Smrg   GLuint i;
229848b8605Smrg   for (i = 0; i < NumExtEntryPoints; i++) {
230848b8605Smrg      if (ExtEntryTable[i].dispatch_offset == offset) {
231848b8605Smrg         return ExtEntryTable[i].name;
232848b8605Smrg      }
233848b8605Smrg   }
234848b8605Smrg   return NULL;
235848b8605Smrg}
236848b8605Smrg
237848b8605Smrg
238848b8605Smrg/**
239848b8605Smrg * strdup() is actually not a standard ANSI C or POSIX routine.
240848b8605Smrg * Irix will not define it if ANSI mode is in effect.
241848b8605Smrg */
242848b8605Smrgstatic char *
243848b8605Smrgstr_dup(const char *str)
244848b8605Smrg{
245848b8605Smrg   char *copy;
246848b8605Smrg   copy = malloc(strlen(str) + 1);
247848b8605Smrg   if (!copy)
248848b8605Smrg      return NULL;
249848b8605Smrg   strcpy(copy, str);
250848b8605Smrg   return copy;
251848b8605Smrg}
252848b8605Smrg
253848b8605Smrg
254848b8605Smrg/**
255848b8605Smrg * Generate new entrypoint
256848b8605Smrg *
257848b8605Smrg * Use a temporary dispatch offset of ~0 (i.e. -1).  Later, when the driver
258848b8605Smrg * calls \c _glapi_add_dispatch we'll put in the proper offset.  If that
259848b8605Smrg * never happens, and the user calls this function, he'll segfault.  That's
260848b8605Smrg * what you get when you try calling a GL function that doesn't really exist.
261848b8605Smrg *
262848b8605Smrg * \param funcName  Name of the function to create an entry-point for.
263848b8605Smrg *
264848b8605Smrg * \sa _glapi_add_entrypoint
265848b8605Smrg */
266848b8605Smrg
267848b8605Smrgstatic struct _glapi_function *
268848b8605Smrgadd_function_name( const char * funcName )
269848b8605Smrg{
270848b8605Smrg   struct _glapi_function * entry = NULL;
271848b8605Smrg   _glapi_proc entrypoint = NULL;
272848b8605Smrg   char * name_dup = NULL;
273848b8605Smrg
274848b8605Smrg   if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS)
275848b8605Smrg      return NULL;
276848b8605Smrg
277848b8605Smrg   if (funcName == NULL)
278848b8605Smrg      return NULL;
279848b8605Smrg
280848b8605Smrg   name_dup = str_dup(funcName);
281848b8605Smrg   if (name_dup == NULL)
282848b8605Smrg      return NULL;
283848b8605Smrg
284848b8605Smrg   entrypoint = generate_entrypoint(~0);
285848b8605Smrg
286848b8605Smrg   if (entrypoint == NULL) {
287848b8605Smrg      free(name_dup);
288848b8605Smrg      return NULL;
289848b8605Smrg   }
290848b8605Smrg
291848b8605Smrg   entry = & ExtEntryTable[NumExtEntryPoints];
292848b8605Smrg   NumExtEntryPoints++;
293848b8605Smrg
294848b8605Smrg   entry->name = name_dup;
295848b8605Smrg   entry->parameter_signature = NULL;
296848b8605Smrg   entry->dispatch_offset = ~0;
297848b8605Smrg   entry->dispatch_stub = entrypoint;
298848b8605Smrg
299848b8605Smrg   return entry;
300848b8605Smrg}
301848b8605Smrg
302848b8605Smrg
303848b8605Smrgstatic struct _glapi_function *
304848b8605Smrgset_entry_info( struct _glapi_function * entry, const char * signature, unsigned offset )
305848b8605Smrg{
306848b8605Smrg   char * sig_dup = NULL;
307848b8605Smrg
308848b8605Smrg   if (signature == NULL)
309848b8605Smrg      return NULL;
310848b8605Smrg
311848b8605Smrg   sig_dup = str_dup(signature);
312848b8605Smrg   if (sig_dup == NULL)
313848b8605Smrg      return NULL;
314848b8605Smrg
315848b8605Smrg   fill_in_entrypoint_offset(entry->dispatch_stub, offset);
316848b8605Smrg
317848b8605Smrg   entry->parameter_signature = sig_dup;
318848b8605Smrg   entry->dispatch_offset = offset;
319848b8605Smrg
320848b8605Smrg   return entry;
321848b8605Smrg}
322848b8605Smrg
323848b8605Smrg
324848b8605Smrg/**
325848b8605Smrg * Fill-in the dispatch stub for the named function.
326848b8605Smrg *
327848b8605Smrg * This function is intended to be called by a hardware driver.  When called,
328b8e80941Smrg * a dispatch stub may be created for the function.  A pointer to this
329848b8605Smrg * dispatch function will be returned by glXGetProcAddress.
330848b8605Smrg *
331848b8605Smrg * \param function_names       Array of pointers to function names that should
332848b8605Smrg *                             share a common dispatch offset.
333848b8605Smrg * \param parameter_signature  String representing the types of the parameters
334848b8605Smrg *                             passed to the named function.  Parameter types
335848b8605Smrg *                             are converted to characters using the following
336848b8605Smrg *                             rules:
337848b8605Smrg *                               - 'i' for \c GLint, \c GLuint, and \c GLenum
338848b8605Smrg *                               - 'p' for any pointer type
339848b8605Smrg *                               - 'f' for \c GLfloat and \c GLclampf
340848b8605Smrg *                               - 'd' for \c GLdouble and \c GLclampd
341848b8605Smrg *
342848b8605Smrg * \returns
343848b8605Smrg * The offset in the dispatch table of the named function.  A pointer to the
344848b8605Smrg * driver's implementation of the named function should be stored at
345848b8605Smrg * \c dispatch_table[\c offset].  Return -1 if error/problem.
346848b8605Smrg *
347848b8605Smrg * \sa glXGetProcAddress
348848b8605Smrg *
349848b8605Smrg * \warning
350848b8605Smrg * This function can only handle up to 8 names at a time.  As far as I know,
351848b8605Smrg * the maximum number of names ever associated with an existing GL function is
352848b8605Smrg * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
353848b8605Smrg * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
354848b8605Smrg * too painful of a limitation.
355848b8605Smrg *
356848b8605Smrg * \todo
357848b8605Smrg * Determine whether or not \c parameter_signature should be allowed to be
358848b8605Smrg * \c NULL.  It doesn't seem like much of a hardship for drivers to have to
359848b8605Smrg * pass in an empty string.
360848b8605Smrg *
361848b8605Smrg * \todo
362848b8605Smrg * Determine if code should be added to reject function names that start with
363848b8605Smrg * 'glX'.
364848b8605Smrg *
365848b8605Smrg * \bug
366848b8605Smrg * Add code to compare \c parameter_signature with the parameter signature of
367848b8605Smrg * a static function.  In order to do that, we need to find a way to \b get
368848b8605Smrg * the parameter signature of a static function.
369848b8605Smrg */
370848b8605Smrg
371848b8605Smrgint
372848b8605Smrg_glapi_add_dispatch( const char * const * function_names,
373848b8605Smrg		     const char * parameter_signature )
374848b8605Smrg{
375848b8605Smrg   static int next_dynamic_offset = FIRST_DYNAMIC_OFFSET;
376848b8605Smrg   const char * const real_sig = (parameter_signature != NULL)
377848b8605Smrg     ? parameter_signature : "";
378848b8605Smrg   struct _glapi_function * entry[8];
379848b8605Smrg   GLboolean is_static[8];
380848b8605Smrg   unsigned i;
381848b8605Smrg   int offset = ~0;
382848b8605Smrg
383848b8605Smrg   init_glapi_relocs_once();
384848b8605Smrg
385848b8605Smrg   (void) memset( is_static, 0, sizeof( is_static ) );
386848b8605Smrg   (void) memset( entry, 0, sizeof( entry ) );
387848b8605Smrg
388848b8605Smrg   /* Find the _single_ dispatch offset for all function names that already
389848b8605Smrg    * exist (and have a dispatch offset).
390848b8605Smrg    */
391848b8605Smrg
392848b8605Smrg   for ( i = 0 ; function_names[i] != NULL ; i++ ) {
393848b8605Smrg      const char * funcName = function_names[i];
394848b8605Smrg      int static_offset;
395848b8605Smrg      int extension_offset;
396848b8605Smrg
397848b8605Smrg      if (funcName[0] != 'g' || funcName[1] != 'l')
398848b8605Smrg         return -1;
399848b8605Smrg
400848b8605Smrg      /* search built-in functions */
401848b8605Smrg      static_offset = get_static_proc_offset(funcName);
402848b8605Smrg
403848b8605Smrg      if (static_offset >= 0) {
404848b8605Smrg
405848b8605Smrg	 is_static[i] = GL_TRUE;
406848b8605Smrg
407848b8605Smrg	 /* FIXME: Make sure the parameter signatures match!  How do we get
408848b8605Smrg	  * FIXME: the parameter signature for static functions?
409848b8605Smrg	  */
410848b8605Smrg
411848b8605Smrg	 if ( (offset != ~0) && (static_offset != offset) ) {
412848b8605Smrg	    return -1;
413848b8605Smrg	 }
414848b8605Smrg
415848b8605Smrg	 offset = static_offset;
416848b8605Smrg
417848b8605Smrg	 continue;
418848b8605Smrg      }
419848b8605Smrg
420848b8605Smrg      /* search added extension functions */
421848b8605Smrg      entry[i] = get_extension_proc(funcName);
422848b8605Smrg
423848b8605Smrg      if (entry[i] != NULL) {
424848b8605Smrg	 extension_offset = entry[i]->dispatch_offset;
425848b8605Smrg
426848b8605Smrg	 /* The offset may be ~0 if the function name was added by
427848b8605Smrg	  * glXGetProcAddress but never filled in by the driver.
428848b8605Smrg	  */
429848b8605Smrg
430848b8605Smrg	 if (extension_offset == ~0) {
431848b8605Smrg	    continue;
432848b8605Smrg	 }
433848b8605Smrg
434848b8605Smrg	 if (strcmp(real_sig, entry[i]->parameter_signature) != 0) {
435848b8605Smrg	    return -1;
436848b8605Smrg	 }
437848b8605Smrg
438848b8605Smrg	 if ( (offset != ~0) && (extension_offset != offset) ) {
439848b8605Smrg	    return -1;
440848b8605Smrg	 }
441848b8605Smrg
442848b8605Smrg	 offset = extension_offset;
443848b8605Smrg      }
444848b8605Smrg   }
445848b8605Smrg
446848b8605Smrg   /* If all function names are either new (or with no dispatch offset),
447848b8605Smrg    * allocate a new dispatch offset.
448848b8605Smrg    */
449848b8605Smrg
450848b8605Smrg   if (offset == ~0) {
451848b8605Smrg      offset = next_dynamic_offset;
452848b8605Smrg      next_dynamic_offset++;
453848b8605Smrg   }
454848b8605Smrg
455848b8605Smrg   /* Fill in the dispatch offset for the new function names (and those with
456848b8605Smrg    * no dispatch offset).
457848b8605Smrg    */
458848b8605Smrg
459848b8605Smrg   for ( i = 0 ; function_names[i] != NULL ; i++ ) {
460848b8605Smrg      if (is_static[i]) {
461848b8605Smrg	 continue;
462848b8605Smrg      }
463848b8605Smrg
464848b8605Smrg      /* generate entrypoints for new function names */
465848b8605Smrg      if (entry[i] == NULL) {
466848b8605Smrg	 entry[i] = add_function_name( function_names[i] );
467848b8605Smrg	 if (entry[i] == NULL) {
468848b8605Smrg	    /* FIXME: Possible memory leak here. */
469848b8605Smrg	    return -1;
470848b8605Smrg	 }
471848b8605Smrg      }
472848b8605Smrg
473848b8605Smrg      if (entry[i]->dispatch_offset == ~0) {
474848b8605Smrg	 set_entry_info( entry[i], real_sig, offset );
475848b8605Smrg      }
476848b8605Smrg   }
477848b8605Smrg
478848b8605Smrg   return offset;
479848b8605Smrg}
480848b8605Smrg
481848b8605Smrg
482848b8605Smrg/**
483848b8605Smrg * Return offset of entrypoint for named function within dispatch table.
484848b8605Smrg */
485848b8605SmrgGLint
486848b8605Smrg_glapi_get_proc_offset(const char *funcName)
487848b8605Smrg{
488848b8605Smrg   GLint offset;
489848b8605Smrg
490848b8605Smrg   /* search extension functions first */
491848b8605Smrg   offset = get_extension_proc_offset(funcName);
492848b8605Smrg   if (offset >= 0)
493848b8605Smrg      return offset;
494848b8605Smrg
495848b8605Smrg   /* search static functions */
496848b8605Smrg   return get_static_proc_offset(funcName);
497848b8605Smrg}
498848b8605Smrg
499848b8605Smrg
500848b8605Smrg
501848b8605Smrg/**
502848b8605Smrg * Return pointer to the named function.  If the function name isn't found
503848b8605Smrg * in the name of static functions, try generating a new API entrypoint on
504848b8605Smrg * the fly with assembly language.
505848b8605Smrg */
506848b8605Smrg_glapi_proc
507848b8605Smrg_glapi_get_proc_address(const char *funcName)
508848b8605Smrg{
509848b8605Smrg   _glapi_proc func;
510848b8605Smrg   struct _glapi_function * entry;
511848b8605Smrg
512848b8605Smrg   init_glapi_relocs_once();
513848b8605Smrg
514b8e80941Smrg#ifdef USE_MGL_NAMESPACE
515b8e80941Smrg   if (funcName && funcName[0] == 'm')
516b8e80941Smrg      funcName++;
517848b8605Smrg#endif
518848b8605Smrg
519b8e80941Smrg  if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
520b8e80941Smrg      return NULL;
521b8e80941Smrg
522848b8605Smrg   /* search extension functions first */
523848b8605Smrg   func = get_extension_proc_address(funcName);
524848b8605Smrg   if (func)
525848b8605Smrg      return func;
526848b8605Smrg
527848b8605Smrg   /* search static functions */
528848b8605Smrg   func = get_static_proc_address(funcName);
529848b8605Smrg   if (func)
530848b8605Smrg      return func;
531848b8605Smrg
532848b8605Smrg   /* generate entrypoint, dispatch offset must be filled in by the driver */
533848b8605Smrg   entry = add_function_name(funcName);
534848b8605Smrg   if (entry == NULL)
535848b8605Smrg      return NULL;
536848b8605Smrg
537848b8605Smrg   return entry->dispatch_stub;
538848b8605Smrg}
539848b8605Smrg
540848b8605Smrg
541848b8605Smrg
542848b8605Smrg/**
543848b8605Smrg * Return the name of the function at the given dispatch offset.
544848b8605Smrg * This is only intended for debugging.
545848b8605Smrg */
546848b8605Smrgconst char *
547848b8605Smrg_glapi_get_proc_name(GLuint offset)
548848b8605Smrg{
549848b8605Smrg   const char * n;
550848b8605Smrg
551848b8605Smrg   /* search built-in functions */
552848b8605Smrg   n = get_static_proc_name(offset);
553848b8605Smrg   if ( n != NULL ) {
554848b8605Smrg      return n;
555848b8605Smrg   }
556848b8605Smrg
557848b8605Smrg   /* search added extension functions */
558848b8605Smrg   return get_extension_proc_name(offset);
559848b8605Smrg}
560848b8605Smrg
561848b8605Smrg
562848b8605Smrg
563848b8605Smrg/**********************************************************************
564848b8605Smrg * GL API table functions.
565848b8605Smrg */
566848b8605Smrg
567848b8605Smrg
568848b8605Smrg/**
569848b8605Smrg * Return size of dispatch table struct as number of functions (or
570848b8605Smrg * slots).
571848b8605Smrg */
572848b8605SmrgGLuint
573848b8605Smrg_glapi_get_dispatch_table_size(void)
574848b8605Smrg{
575848b8605Smrg   /*
576848b8605Smrg    * The dispatch table size (number of entries) is the size of the
577848b8605Smrg    * _glapi_table struct plus the number of dynamic entries we can add.
578848b8605Smrg    * The extra slots can be filled in by DRI drivers that register new
579848b8605Smrg    * extension functions.
580848b8605Smrg    */
581848b8605Smrg   return FIRST_DYNAMIC_OFFSET + MAX_EXTENSION_FUNCS;
582848b8605Smrg}
583