1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2006 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/* 27 * This file manages the OpenGL API dispatch layer. 28 * The dispatch table (struct _glapi_table) is basically just a list 29 * of function pointers. 30 * There are functions to set/get the current dispatch table for the 31 * current thread and to manage registration/dispatch of dynamically 32 * added extension functions. 33 * 34 * It's intended that this file and the other glapi*.[ch] files are 35 * flexible enough to be reused in several places: XFree86, DRI- 36 * based libGL.so, and perhaps the SGI SI. 37 * 38 * NOTE: There are no dependencies on Mesa in this code. 39 * 40 * Versions (API changes): 41 * 2000/02/23 - original version for Mesa 3.3 and XFree86 4.0 42 * 2001/01/16 - added dispatch override feature for Mesa 3.5 43 * 2002/06/28 - added _glapi_set_warning_func(), Mesa 4.1. 44 * 2002/10/01 - _glapi_get_proc_address() will now generate new entrypoints 45 * itself (using offset ~0). _glapi_add_entrypoint() can be 46 * called afterward and it'll fill in the correct dispatch 47 * offset. This allows DRI libGL to avoid probing for DRI 48 * drivers! No changes to the public glapi interface. 49 */ 50 51 52 53#ifdef HAVE_DIX_CONFIG_H 54 55#include <dix-config.h> 56#include <X11/Xfuncproto.h> 57#include <os.h> 58#define PUBLIC _X_EXPORT 59 60#else 61 62#include "glheader.h" 63 64#endif 65 66#include <stdlib.h> 67#include <string.h> 68#ifdef DEBUG 69#include <assert.h> 70#endif 71 72#include "glapi.h" 73#include "glapioffsets.h" 74#include "glapitable.h" 75 76#if defined(PTHREADS) || defined(GLX_USE_TLS) 77static void init_glapi_relocs(void); 78#endif 79 80/** 81 * \name Current dispatch and current context control variables 82 * 83 * Depending on whether or not multithreading is support, and the type of 84 * support available, several variables are used to store the current context 85 * pointer and the current dispatch table pointer. In the non-threaded case, 86 * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this 87 * purpose. 88 * 89 * In the "normal" threaded case, the variables \c _glapi_Dispatch and 90 * \c _glapi_Context will be \c NULL if an application is detected as being 91 * multithreaded. Single-threaded applications will use \c _glapi_Dispatch 92 * and \c _glapi_Context just like the case without any threading support. 93 * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state 94 * data \c _gl_DispatchTSD and \c ContextTSD are used. Drivers and the 95 * static dispatch functions access these variables via \c _glapi_get_dispatch 96 * and \c _glapi_get_context. 97 * 98 * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are 99 * hardcoded to \c NULL. Instead the TLS variables \c _glapi_tls_Dispatch and 100 * \c _glapi_tls_Context are used. Having \c _glapi_Dispatch and 101 * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability 102 * between TLS enabled loaders and non-TLS DRI drivers. 103 */ 104/*@{*/ 105#if defined(GLX_USE_TLS) 106 107PUBLIC TLS struct _glapi_table * _glapi_tls_Dispatch 108 __attribute__((tls_model("initial-exec"))) = NULL; 109 110PUBLIC TLS void * _glapi_tls_Context 111 __attribute__((tls_model("initial-exec"))); 112 113PUBLIC const struct _glapi_table *_glapi_Dispatch = NULL; 114PUBLIC const void *_glapi_Context = NULL; 115 116#else 117 118#if defined(THREADS) 119 120_glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */ 121static _glthread_TSD ContextTSD; /**< Per-thread context pointer */ 122 123#if defined(WIN32_THREADS) 124void FreeTSD(_glthread_TSD *p); 125void FreeAllTSD(void) 126{ 127 FreeTSD(&_gl_DispatchTSD); 128 FreeTSD(&ContextTSD); 129} 130#endif /* defined(WIN32_THREADS) */ 131 132#endif /* defined(THREADS) */ 133 134PUBLIC struct _glapi_table *_glapi_Dispatch = NULL; 135PUBLIC void *_glapi_Context = NULL; 136 137#endif /* defined(GLX_USE_TLS) */ 138/*@}*/ 139 140/* 141 * xserver's gl is not multithreaded, we promise. 142 */ 143PUBLIC void 144_glapi_check_multithread(void) 145{ 146} 147 148/** 149 * Set the current context pointer for this thread. 150 * The context pointer is an opaque type which should be cast to 151 * void from the real context pointer type. 152 */ 153PUBLIC void 154_glapi_set_context(void *context) 155{ 156#if defined(GLX_USE_TLS) 157 _glapi_tls_Context = context; 158#elif defined(THREADS) 159 _glthread_SetTSD(&ContextTSD, context); 160 _glapi_Context = context; 161#else 162 _glapi_Context = context; 163#endif 164} 165 166 167 168/** 169 * Get the current context pointer for this thread. 170 * The context pointer is an opaque type which should be cast from 171 * void to the real context pointer type. 172 */ 173PUBLIC void * 174_glapi_get_context(void) 175{ 176#if defined(GLX_USE_TLS) 177 return _glapi_tls_Context; 178#else 179 return _glapi_Context; 180#endif 181} 182 183 184 185/** 186 * Set the global or per-thread dispatch table pointer. 187 */ 188PUBLIC void 189_glapi_set_dispatch(struct _glapi_table *dispatch) 190{ 191#if defined(PTHREADS) || defined(GLX_USE_TLS) 192 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 193 pthread_once( & once_control, init_glapi_relocs ); 194#endif 195 196#if defined(GLX_USE_TLS) 197 _glapi_tls_Dispatch = dispatch; 198#elif defined(THREADS) 199 _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch); 200 _glapi_Dispatch = dispatch; 201#else /*THREADS*/ 202 _glapi_Dispatch = dispatch; 203#endif /*THREADS*/ 204} 205 206 207 208/** 209 * Return pointer to current dispatch table for calling thread. 210 */ 211PUBLIC struct _glapi_table * 212_glapi_get_dispatch(void) 213{ 214 struct _glapi_table * api; 215#if defined(GLX_USE_TLS) 216 api = _glapi_tls_Dispatch; 217#else 218 api = _glapi_Dispatch; 219#endif 220 return api; 221} 222 223 224 225/*** 226 *** The rest of this file is pretty much concerned with GetProcAddress 227 *** functionality. 228 ***/ 229 230#if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS) 231# define DISPATCH_FUNCTION_SIZE 16 232#elif defined(USE_X86_ASM) 233# if defined(THREADS) && !defined(GLX_USE_TLS) 234# define DISPATCH_FUNCTION_SIZE 32 235# else 236# define DISPATCH_FUNCTION_SIZE 16 237# endif 238#endif 239 240#if !defined(DISPATCH_FUNCTION_SIZE) && !defined(XFree86Server) && !defined(XGLServer) 241# define NEED_FUNCTION_POINTER 242#endif 243 244/* The code in this file is auto-generated with Python */ 245#include "glprocs.h" 246 247 248/** 249 * Search the table of static entrypoint functions for the named function 250 * and return the corresponding glprocs_table_t entry. 251 */ 252static const glprocs_table_t * 253find_entry( const char * n ) 254{ 255 GLuint i; 256 for (i = 0; static_functions[i].Name_offset >= 0; i++) { 257 const char *testName = gl_string_table + static_functions[i].Name_offset; 258 if (strcmp(testName, n) == 0) { 259 return &static_functions[i]; 260 } 261 } 262 return NULL; 263} 264 265 266/** 267 * Return dispatch table offset of the named static (built-in) function. 268 * Return -1 if function not found. 269 */ 270static GLint 271get_static_proc_offset(const char *funcName) 272{ 273 const glprocs_table_t * const f = find_entry( funcName ); 274 if (f) { 275 return f->Offset; 276 } 277 return -1; 278} 279 280 281#if !defined(XFree86Server) && !defined(XGLServer) 282#ifdef USE_X86_ASM 283 284#if defined( GLX_USE_TLS ) 285extern GLubyte gl_dispatch_functions_start[]; 286extern GLubyte gl_dispatch_functions_end[]; 287#else 288extern const GLubyte gl_dispatch_functions_start[]; 289#endif 290 291#endif /* USE_X86_ASM */ 292 293 294/** 295 * Return dispatch function address for the named static (built-in) function. 296 * Return NULL if function not found. 297 */ 298static _glapi_proc 299get_static_proc_address(const char *funcName) 300{ 301 const glprocs_table_t * const f = find_entry( funcName ); 302 if (f) { 303#if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING) 304 return (f->Address == NULL) 305 ? (_glapi_proc) (gl_dispatch_functions_start 306 + (DISPATCH_FUNCTION_SIZE * f->Offset)) 307 : f->Address; 308#elif defined(DISPATCH_FUNCTION_SIZE) 309 return (_glapi_proc) (gl_dispatch_functions_start 310 + (DISPATCH_FUNCTION_SIZE * f->Offset)); 311#else 312 return f->Address; 313#endif 314 } 315 else { 316 return NULL; 317 } 318} 319 320#endif /* !defined(XFree86Server) && !defined(XGLServer) */ 321 322/********************************************************************** 323 * Extension function management. 324 */ 325 326/* 327 * Number of extension functions which we can dynamically add at runtime. 328 */ 329#define MAX_EXTENSION_FUNCS 300 330 331 332/* 333 * The dispatch table size (number of entries) is the size of the 334 * _glapi_table struct plus the number of dynamic entries we can add. 335 * The extra slots can be filled in by DRI drivers that register new extension 336 * functions. 337 */ 338#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS) 339 340 341/** 342 * Track information about a function added to the GL API. 343 */ 344struct _glapi_function { 345 /** 346 * Name of the function. 347 */ 348 const char * name; 349 350 /** 351 * Text string that describes the types of the parameters passed to the 352 * named function. Parameter types are converted to characters using the 353 * following rules: 354 * - 'i' for \c GLint, \c GLuint, and \c GLenum 355 * - 'p' for any pointer type 356 * - 'f' for \c GLfloat and \c GLclampf 357 * - 'd' for \c GLdouble and \c GLclampd 358 */ 359 const char * parameter_signature; 360 361 /** 362 * Offset in the dispatch table where the pointer to the real function is 363 * located. If the driver has not requested that the named function be 364 * added to the dispatch table, this will have the value ~0. 365 */ 366 unsigned dispatch_offset; 367}; 368 369static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS]; 370static GLuint NumExtEntryPoints = 0; 371 372/** 373 * Generate new entrypoint 374 * 375 * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver 376 * calls \c _glapi_add_dispatch we'll put in the proper offset. If that 377 * never happens, and the user calls this function, he'll segfault. That's 378 * what you get when you try calling a GL function that doesn't really exist. 379 * 380 * \param funcName Name of the function to create an entry-point for. 381 * 382 * \sa _glapi_add_entrypoint 383 */ 384 385static struct _glapi_function * 386add_function_name( const char * funcName ) 387{ 388 struct _glapi_function * entry = NULL; 389 390 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) { 391 entry = &ExtEntryTable[NumExtEntryPoints]; 392 393 ExtEntryTable[NumExtEntryPoints].name = strdup(funcName); 394 ExtEntryTable[NumExtEntryPoints].parameter_signature = NULL; 395 ExtEntryTable[NumExtEntryPoints].dispatch_offset = ~0; 396 NumExtEntryPoints++; 397 } 398 399 return entry; 400} 401 402 403/** 404 * Fill-in the dispatch stub for the named function. 405 * 406 * This function is intended to be called by a hardware driver. When called, 407 * a dispatch stub may be created created for the function. A pointer to this 408 * dispatch function will be returned by glXGetProcAddress. 409 * 410 * \param function_names Array of pointers to function names that should 411 * share a common dispatch offset. 412 * \param parameter_signature String representing the types of the parameters 413 * passed to the named function. Parameter types 414 * are converted to characters using the following 415 * rules: 416 * - 'i' for \c GLint, \c GLuint, and \c GLenum 417 * - 'p' for any pointer type 418 * - 'f' for \c GLfloat and \c GLclampf 419 * - 'd' for \c GLdouble and \c GLclampd 420 * 421 * \returns 422 * The offset in the dispatch table of the named function. A pointer to the 423 * driver's implementation of the named function should be stored at 424 * \c dispatch_table[\c offset]. 425 * 426 * \sa glXGetProcAddress 427 * 428 * \warning 429 * This function can only handle up to 8 names at a time. As far as I know, 430 * the maximum number of names ever associated with an existing GL function is 431 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT, 432 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be 433 * too painful of a limitation. 434 * 435 * \todo 436 * Determine whether or not \c parameter_signature should be allowed to be 437 * \c NULL. It doesn't seem like much of a hardship for drivers to have to 438 * pass in an empty string. 439 * 440 * \todo 441 * Determine if code should be added to reject function names that start with 442 * 'glX'. 443 * 444 * \bug 445 * Add code to compare \c parameter_signature with the parameter signature of 446 * a static function. In order to do that, we need to find a way to \b get 447 * the parameter signature of a static function. 448 */ 449 450PUBLIC int 451_glapi_add_dispatch( const char * const * function_names, 452 const char * parameter_signature ) 453{ 454 static int next_dynamic_offset = _gloffset_FIRST_DYNAMIC; 455 const char * const real_sig = (parameter_signature != NULL) 456 ? parameter_signature : ""; 457 struct _glapi_function * entry[8]; 458 GLboolean is_static[8]; 459 unsigned i; 460 unsigned j; 461 int offset = ~0; 462 int new_offset; 463 464 465 (void) memset(is_static, 0, sizeof(is_static)); 466 (void) memset(entry, 0, sizeof(entry)); 467 468 for (i = 0 ; function_names[i] != NULL ; i++) { 469 /* Do some trivial validation on the name of the function. */ 470 471 if (function_names[i][0] != 'g' || function_names[i][1] != 'l') 472 return GL_FALSE; 473 474 /* Determine if the named function already exists. If the function does 475 * exist, it must have the same parameter signature as the function 476 * being added. 477 */ 478 479 new_offset = get_static_proc_offset(function_names[i]); 480 if (new_offset >= 0) { 481 /* FIXME: Make sure the parameter signatures match! How do we get 482 * FIXME: the parameter signature for static functions? 483 */ 484 485 if ((offset != ~0) && (new_offset != offset)) { 486 return -1; 487 } 488 489 is_static[i] = GL_TRUE; 490 offset = new_offset; 491 } 492 493 for (j = 0; j < NumExtEntryPoints; j++) { 494 if (strcmp(ExtEntryTable[j].name, function_names[i]) == 0) { 495 /* The offset may be ~0 if the function name was added by 496 * glXGetProcAddress but never filled in by the driver. 497 */ 498 499 if (ExtEntryTable[j].dispatch_offset != ~0) { 500 if (strcmp(real_sig, ExtEntryTable[j].parameter_signature) != 0) 501 return -1; 502 503 if ((offset != ~0) && (ExtEntryTable[j].dispatch_offset != offset)) { 504 return -1; 505 } 506 507 offset = ExtEntryTable[j].dispatch_offset; 508 } 509 510 entry[i] = & ExtEntryTable[j]; 511 break; 512 } 513 } 514 } 515 516 if (offset == ~0) { 517 offset = next_dynamic_offset; 518 next_dynamic_offset++; 519 } 520 521 for (i = 0 ; function_names[i] != NULL ; i++) { 522 if (!is_static[i]) { 523 if (entry[i] == NULL) { 524 entry[i] = add_function_name(function_names[i]); 525 if (entry[i] == NULL) 526 return -1; 527 } 528 529 entry[i]->parameter_signature = strdup(real_sig); 530 entry[i]->dispatch_offset = offset; 531 } 532 } 533 534 return offset; 535} 536 537/* 538 * glXGetProcAddress doesn't exist in the protocol, the drivers never call 539 * this themselves, and neither does the server. warn if it happens though. 540 */ 541PUBLIC _glapi_proc 542_glapi_get_proc_address(const char *funcName) 543{ 544 ErrorF("_glapi_get_proc_address called!\n"); 545 return NULL; 546} 547 548/** 549 * Return size of dispatch table struct as number of functions (or 550 * slots). 551 */ 552PUBLIC GLuint 553_glapi_get_dispatch_table_size(void) 554{ 555 return DISPATCH_TABLE_SIZE; 556} 557 558#if defined(PTHREADS) || defined(GLX_USE_TLS) 559/** 560 * Perform platform-specific GL API entry-point fixups. 561 */ 562static void 563init_glapi_relocs( void ) 564{ 565#if defined(USE_X86_ASM) && defined(GLX_USE_TLS) && !defined(GLX_X86_READONLY_TEXT) 566 extern unsigned long _x86_get_dispatch(void); 567 char run_time_patch[] = { 568 0x65, 0xa1, 0, 0, 0, 0 /* movl %gs:0,%eax */ 569 }; 570 GLuint *offset = (GLuint *) &run_time_patch[2]; /* 32-bits for x86/32 */ 571 const GLubyte * const get_disp = (const GLubyte *) run_time_patch; 572 GLubyte * curr_func = (GLubyte *) gl_dispatch_functions_start; 573 574 *offset = _x86_get_dispatch(); 575 while ( curr_func != (GLubyte *) gl_dispatch_functions_end ) { 576 (void) memcpy( curr_func, get_disp, sizeof(run_time_patch)); 577 curr_func += DISPATCH_FUNCTION_SIZE; 578 } 579#endif 580} 581#endif /* defined(PTHREADS) || defined(GLX_USE_TLS) */ 582