1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file glapi_getproc.c
27 *
28 * Code for implementing glXGetProcAddress(), etc.
29 * This was originally in glapi.c but refactored out.
30 */
31
32
33 #include <assert.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include "glapi/glapi_priv.h"
37 #include "glapitable.h"
38
39
40 #define FIRST_DYNAMIC_OFFSET (sizeof(struct _glapi_table) / sizeof(void *))
41
42
43
44 /**********************************************************************
45 * Static function management.
46 */
47
48
49 #if !defined(DISPATCH_FUNCTION_SIZE)
50 # define NEED_FUNCTION_POINTER
51 #endif
52 #include "glprocs.h"
53
54
55 /**
56 * Search the table of static entrypoint functions for the named function
57 * and return the corresponding glprocs_table_t entry.
58 */
59 static const glprocs_table_t *
get_static_proc(const char * n)60 get_static_proc( const char * n )
61 {
62 GLuint i;
63 for (i = 0; static_functions[i].Name_offset >= 0; i++) {
64 const char *testName = gl_string_table + static_functions[i].Name_offset;
65 if (strcmp(testName, n) == 0)
66 {
67 return &static_functions[i];
68 }
69 }
70 return NULL;
71 }
72
73
74 /**
75 * Return dispatch table offset of the named static (built-in) function.
76 * Return -1 if function not found.
77 */
78 static GLint
get_static_proc_offset(const char * funcName)79 get_static_proc_offset(const char *funcName)
80 {
81 const glprocs_table_t * const f = get_static_proc( funcName );
82 if (f == NULL) {
83 return -1;
84 }
85
86 return f->Offset;
87 }
88
89
90
91 /**
92 * Return dispatch function address for the named static (built-in) function.
93 * Return NULL if function not found.
94 */
95 static _glapi_proc
get_static_proc_address(const char * funcName)96 get_static_proc_address(const char *funcName)
97 {
98 const glprocs_table_t * const f = get_static_proc( funcName );
99 if (f == NULL) {
100 return NULL;
101 }
102
103 #if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
104 return (f->Address == NULL)
105 ? get_entrypoint_address(f->Offset)
106 : f->Address;
107 #elif defined(DISPATCH_FUNCTION_SIZE)
108 return get_entrypoint_address(f->Offset);
109 #else
110 return f->Address;
111 #endif
112 }
113
114
115
116 /**
117 * Return the name of the function at the given offset in the dispatch
118 * table. For debugging only.
119 */
120 static const char *
get_static_proc_name(GLuint offset)121 get_static_proc_name( GLuint offset )
122 {
123 GLuint i;
124 for (i = 0; static_functions[i].Name_offset >= 0; i++) {
125 if (static_functions[i].Offset == offset) {
126 return gl_string_table + static_functions[i].Name_offset;
127 }
128 }
129 return NULL;
130 }
131
132
133
134 /**********************************************************************
135 * Extension function management.
136 */
137
138
139 /**
140 * Track information about a function added to the GL API.
141 */
142 struct _glapi_function {
143 /**
144 * Name of the function.
145 */
146 const char * name;
147
148
149 /**
150 * Text string that describes the types of the parameters passed to the
151 * named function. Parameter types are converted to characters using the
152 * following rules:
153 * - 'i' for \c GLint, \c GLuint, and \c GLenum
154 * - 'p' for any pointer type
155 * - 'f' for \c GLfloat and \c GLclampf
156 * - 'd' for \c GLdouble and \c GLclampd
157 */
158 const char * parameter_signature;
159
160
161 /**
162 * Offset in the dispatch table where the pointer to the real function is
163 * located. If the driver has not requested that the named function be
164 * added to the dispatch table, this will have the value ~0.
165 */
166 unsigned dispatch_offset;
167
168
169 /**
170 * Pointer to the dispatch stub for the named function.
171 *
172 * \todo
173 * The semantic of this field should be changed slightly. Currently, it
174 * is always expected to be non-\c NULL. However, it would be better to
175 * only allocate the entry-point stub when the application requests the
176 * function via \c glXGetProcAddress. This would save memory for all the
177 * functions that the driver exports but that the application never wants
178 * to call.
179 */
180 _glapi_proc dispatch_stub;
181 };
182
183
184 static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
185 static GLuint NumExtEntryPoints = 0;
186
187
188 static struct _glapi_function *
get_extension_proc(const char * funcName)189 get_extension_proc(const char *funcName)
190 {
191 GLuint i;
192 for (i = 0; i < NumExtEntryPoints; i++) {
193 if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
194 return & ExtEntryTable[i];
195 }
196 }
197 return NULL;
198 }
199
200
201 static GLint
get_extension_proc_offset(const char * funcName)202 get_extension_proc_offset(const char *funcName)
203 {
204 const struct _glapi_function * const f = get_extension_proc( funcName );
205 if (f == NULL) {
206 return -1;
207 }
208
209 return f->dispatch_offset;
210 }
211
212
213 static _glapi_proc
get_extension_proc_address(const char * funcName)214 get_extension_proc_address(const char *funcName)
215 {
216 const struct _glapi_function * const f = get_extension_proc( funcName );
217 if (f == NULL) {
218 return NULL;
219 }
220
221 return f->dispatch_stub;
222 }
223
224
225 static const char *
get_extension_proc_name(GLuint offset)226 get_extension_proc_name(GLuint offset)
227 {
228 GLuint i;
229 for (i = 0; i < NumExtEntryPoints; i++) {
230 if (ExtEntryTable[i].dispatch_offset == offset) {
231 return ExtEntryTable[i].name;
232 }
233 }
234 return NULL;
235 }
236
237
238 /**
239 * strdup() is actually not a standard ANSI C or POSIX routine.
240 * Irix will not define it if ANSI mode is in effect.
241 */
242 static char *
str_dup(const char * str)243 str_dup(const char *str)
244 {
245 char *copy;
246 copy = malloc(strlen(str) + 1);
247 if (!copy)
248 return NULL;
249 strcpy(copy, str);
250 return copy;
251 }
252
253
254 /**
255 * Generate new entrypoint
256 *
257 * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver
258 * calls \c _glapi_add_dispatch we'll put in the proper offset. If that
259 * never happens, and the user calls this function, he'll segfault. That's
260 * what you get when you try calling a GL function that doesn't really exist.
261 *
262 * \param funcName Name of the function to create an entry-point for.
263 *
264 * \sa _glapi_add_entrypoint
265 */
266
267 static struct _glapi_function *
add_function_name(const char * funcName)268 add_function_name( const char * funcName )
269 {
270 struct _glapi_function * entry = NULL;
271 _glapi_proc entrypoint = NULL;
272 char * name_dup = NULL;
273
274 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS)
275 return NULL;
276
277 if (funcName == NULL)
278 return NULL;
279
280 name_dup = str_dup(funcName);
281 if (name_dup == NULL)
282 return NULL;
283
284 entrypoint = generate_entrypoint(~0);
285
286 if (entrypoint == NULL) {
287 free(name_dup);
288 return NULL;
289 }
290
291 entry = & ExtEntryTable[NumExtEntryPoints];
292 NumExtEntryPoints++;
293
294 entry->name = name_dup;
295 entry->parameter_signature = NULL;
296 entry->dispatch_offset = ~0;
297 entry->dispatch_stub = entrypoint;
298
299 return entry;
300 }
301
302
303 static struct _glapi_function *
set_entry_info(struct _glapi_function * entry,const char * signature,unsigned offset)304 set_entry_info( struct _glapi_function * entry, const char * signature, unsigned offset )
305 {
306 char * sig_dup = NULL;
307
308 if (signature == NULL)
309 return NULL;
310
311 sig_dup = str_dup(signature);
312 if (sig_dup == NULL)
313 return NULL;
314
315 fill_in_entrypoint_offset(entry->dispatch_stub, offset);
316
317 entry->parameter_signature = sig_dup;
318 entry->dispatch_offset = offset;
319
320 return entry;
321 }
322
323
324 /**
325 * Fill-in the dispatch stub for the named function.
326 *
327 * This function is intended to be called by a hardware driver. When called,
328 * a dispatch stub may be created for the function. A pointer to this
329 * dispatch function will be returned by glXGetProcAddress.
330 *
331 * \param function_names Array of pointers to function names that should
332 * share a common dispatch offset.
333 * \param parameter_signature String representing the types of the parameters
334 * passed to the named function. Parameter types
335 * are converted to characters using the following
336 * rules:
337 * - 'i' for \c GLint, \c GLuint, and \c GLenum
338 * - 'p' for any pointer type
339 * - 'f' for \c GLfloat and \c GLclampf
340 * - 'd' for \c GLdouble and \c GLclampd
341 *
342 * \returns
343 * The offset in the dispatch table of the named function. A pointer to the
344 * driver's implementation of the named function should be stored at
345 * \c dispatch_table[\c offset]. Return -1 if error/problem.
346 *
347 * \sa glXGetProcAddress
348 *
349 * \warning
350 * This function can only handle up to 8 names at a time. As far as I know,
351 * the maximum number of names ever associated with an existing GL function is
352 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
353 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
354 * too painful of a limitation.
355 *
356 * \todo
357 * Determine whether or not \c parameter_signature should be allowed to be
358 * \c NULL. It doesn't seem like much of a hardship for drivers to have to
359 * pass in an empty string.
360 *
361 * \todo
362 * Determine if code should be added to reject function names that start with
363 * 'glX'.
364 *
365 * \bug
366 * Add code to compare \c parameter_signature with the parameter signature of
367 * a static function. In order to do that, we need to find a way to \b get
368 * the parameter signature of a static function.
369 */
370
371 int
_glapi_add_dispatch(const char * const * function_names,const char * parameter_signature)372 _glapi_add_dispatch( const char * const * function_names,
373 const char * parameter_signature )
374 {
375 static int next_dynamic_offset = FIRST_DYNAMIC_OFFSET;
376 const char * const real_sig = (parameter_signature != NULL)
377 ? parameter_signature : "";
378 struct _glapi_function * entry[8];
379 GLboolean is_static[8];
380 unsigned i;
381 int offset = ~0;
382
383 init_glapi_relocs_once();
384
385 (void) memset( is_static, 0, sizeof( is_static ) );
386 (void) memset( entry, 0, sizeof( entry ) );
387
388 /* Find the _single_ dispatch offset for all function names that already
389 * exist (and have a dispatch offset).
390 */
391
392 for ( i = 0 ; function_names[i] != NULL ; i++ ) {
393 const char * funcName = function_names[i];
394 int static_offset;
395 int extension_offset;
396
397 if (funcName[0] != 'g' || funcName[1] != 'l')
398 return -1;
399
400 /* search built-in functions */
401 static_offset = get_static_proc_offset(funcName);
402
403 if (static_offset >= 0) {
404
405 is_static[i] = GL_TRUE;
406
407 /* FIXME: Make sure the parameter signatures match! How do we get
408 * FIXME: the parameter signature for static functions?
409 */
410
411 if ( (offset != ~0) && (static_offset != offset) ) {
412 return -1;
413 }
414
415 offset = static_offset;
416
417 continue;
418 }
419
420 /* search added extension functions */
421 entry[i] = get_extension_proc(funcName);
422
423 if (entry[i] != NULL) {
424 extension_offset = entry[i]->dispatch_offset;
425
426 /* The offset may be ~0 if the function name was added by
427 * glXGetProcAddress but never filled in by the driver.
428 */
429
430 if (extension_offset == ~0) {
431 continue;
432 }
433
434 if (strcmp(real_sig, entry[i]->parameter_signature) != 0) {
435 return -1;
436 }
437
438 if ( (offset != ~0) && (extension_offset != offset) ) {
439 return -1;
440 }
441
442 offset = extension_offset;
443 }
444 }
445
446 /* If all function names are either new (or with no dispatch offset),
447 * allocate a new dispatch offset.
448 */
449
450 if (offset == ~0) {
451 offset = next_dynamic_offset;
452 next_dynamic_offset++;
453 }
454
455 /* Fill in the dispatch offset for the new function names (and those with
456 * no dispatch offset).
457 */
458
459 for ( i = 0 ; function_names[i] != NULL ; i++ ) {
460 if (is_static[i]) {
461 continue;
462 }
463
464 /* generate entrypoints for new function names */
465 if (entry[i] == NULL) {
466 entry[i] = add_function_name( function_names[i] );
467 if (entry[i] == NULL) {
468 /* FIXME: Possible memory leak here. */
469 return -1;
470 }
471 }
472
473 if (entry[i]->dispatch_offset == ~0) {
474 set_entry_info( entry[i], real_sig, offset );
475 }
476 }
477
478 return offset;
479 }
480
481
482 /**
483 * Return offset of entrypoint for named function within dispatch table.
484 */
485 GLint
_glapi_get_proc_offset(const char * funcName)486 _glapi_get_proc_offset(const char *funcName)
487 {
488 GLint offset;
489
490 /* search extension functions first */
491 offset = get_extension_proc_offset(funcName);
492 if (offset >= 0)
493 return offset;
494
495 /* search static functions */
496 return get_static_proc_offset(funcName);
497 }
498
499
500
501 /**
502 * Return pointer to the named function. If the function name isn't found
503 * in the name of static functions, try generating a new API entrypoint on
504 * the fly with assembly language.
505 */
506 _glapi_proc
_glapi_get_proc_address(const char * funcName)507 _glapi_get_proc_address(const char *funcName)
508 {
509 _glapi_proc func;
510 struct _glapi_function * entry;
511
512 init_glapi_relocs_once();
513
514 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
515 return NULL;
516
517 /* search extension functions first */
518 func = get_extension_proc_address(funcName);
519 if (func)
520 return func;
521
522 /* search static functions */
523 func = get_static_proc_address(funcName);
524 if (func)
525 return func;
526
527 /* generate entrypoint, dispatch offset must be filled in by the driver */
528 entry = add_function_name(funcName);
529 if (entry == NULL)
530 return NULL;
531
532 return entry->dispatch_stub;
533 }
534
535
536
537 /**
538 * Return the name of the function at the given dispatch offset.
539 * This is only intended for debugging.
540 */
541 const char *
_glapi_get_proc_name(GLuint offset)542 _glapi_get_proc_name(GLuint offset)
543 {
544 const char * n;
545
546 /* search built-in functions */
547 n = get_static_proc_name(offset);
548 if ( n != NULL ) {
549 return n;
550 }
551
552 /* search added extension functions */
553 return get_extension_proc_name(offset);
554 }
555
556
557
558 /**********************************************************************
559 * GL API table functions.
560 */
561
562
563 /**
564 * Return size of dispatch table struct as number of functions (or
565 * slots).
566 */
567 GLuint
_glapi_get_dispatch_table_size(void)568 _glapi_get_dispatch_table_size(void)
569 {
570 /*
571 * The dispatch table size (number of entries) is the size of the
572 * _glapi_table struct plus the number of dynamic entries we can add.
573 * The extra slots can be filled in by DRI drivers that register new
574 * extension functions.
575 */
576 return FIRST_DYNAMIC_OFFSET + MAX_EXTENSION_FUNCS;
577 }
578