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 "glapi/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 "glapi/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 * 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 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 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 * 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 * 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 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 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 * 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 * 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 * 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 * 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 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 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 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 #ifdef USE_MGL_NAMESPACE 515 if (funcName && funcName[0] == 'm') 516 funcName++; 517 #endif 518 519 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l') 520 return NULL; 521 522 /* search extension functions first */ 523 func = get_extension_proc_address(funcName); 524 if (func) 525 return func; 526 527 /* search static functions */ 528 func = get_static_proc_address(funcName); 529 if (func) 530 return func; 531 532 /* generate entrypoint, dispatch offset must be filled in by the driver */ 533 entry = add_function_name(funcName); 534 if (entry == NULL) 535 return NULL; 536 537 return entry->dispatch_stub; 538 } 539 540 541 542 /** 543 * Return the name of the function at the given dispatch offset. 544 * This is only intended for debugging. 545 */ 546 const char * 547 _glapi_get_proc_name(GLuint offset) 548 { 549 const char * n; 550 551 /* search built-in functions */ 552 n = get_static_proc_name(offset); 553 if ( n != NULL ) { 554 return n; 555 } 556 557 /* search added extension functions */ 558 return get_extension_proc_name(offset); 559 } 560 561 562 563 /********************************************************************** 564 * GL API table functions. 565 */ 566 567 568 /** 569 * Return size of dispatch table struct as number of functions (or 570 * slots). 571 */ 572 GLuint 573 _glapi_get_dispatch_table_size(void) 574 { 575 /* 576 * The dispatch table size (number of entries) is the size of the 577 * _glapi_table struct plus the number of dynamic entries we can add. 578 * The extra slots can be filled in by DRI drivers that register new 579 * extension functions. 580 */ 581 return FIRST_DYNAMIC_OFFSET + MAX_EXTENSION_FUNCS; 582 } 583