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