gallium/draw: initial code to properly support llvm in the draw module
[mesa.git] / src / mesa / glapi / glapi_getproc.c
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 <stdlib.h>
34 #include <string.h>
35 #include "main/glheader.h"
36 #include "main/compiler.h"
37 #include "glapi/glapi.h"
38 #include "glapi/glapioffsets.h"
39 #include "glapi/glapitable.h"
40
41
42 static void
43 fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset);
44
45
46 /**
47 * strdup() is actually not a standard ANSI C or POSIX routine.
48 * Irix will not define it if ANSI mode is in effect.
49 */
50 static char *
51 str_dup(const char *str)
52 {
53 char *copy;
54 copy = (char*) malloc(strlen(str) + 1);
55 if (!copy)
56 return NULL;
57 strcpy(copy, str);
58 return copy;
59 }
60
61
62
63 #if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS)
64 # define DISPATCH_FUNCTION_SIZE 16
65 #elif defined(USE_X86_ASM)
66 # if defined(THREADS) && !defined(GLX_USE_TLS)
67 # define DISPATCH_FUNCTION_SIZE 32
68 # else
69 # define DISPATCH_FUNCTION_SIZE 16
70 # endif
71 #endif
72
73 #if !defined(DISPATCH_FUNCTION_SIZE) && !defined(XFree86Server) && !defined(XGLServer)
74 # define NEED_FUNCTION_POINTER
75 #endif
76
77 /* The code in this file is auto-generated with Python */
78 #include "glapi/glprocs.h"
79
80
81 /**
82 * Search the table of static entrypoint functions for the named function
83 * and return the corresponding glprocs_table_t entry.
84 */
85 static const glprocs_table_t *
86 find_entry( const char * n )
87 {
88 GLuint i;
89 for (i = 0; static_functions[i].Name_offset >= 0; i++) {
90 const char *testName = gl_string_table + static_functions[i].Name_offset;
91 #ifdef MANGLE
92 /* skip the "m" prefix on the name */
93 if (strcmp(testName, n + 1) == 0)
94 #else
95 if (strcmp(testName, n) == 0)
96 #endif
97 {
98 return &static_functions[i];
99 }
100 }
101 return NULL;
102 }
103
104
105 /**
106 * Return dispatch table offset of the named static (built-in) function.
107 * Return -1 if function not found.
108 */
109 static GLint
110 get_static_proc_offset(const char *funcName)
111 {
112 const glprocs_table_t * const f = find_entry( funcName );
113 if (f) {
114 return f->Offset;
115 }
116 return -1;
117 }
118
119
120 #if !defined(XFree86Server) && !defined(XGLServer)
121 #ifdef USE_X86_ASM
122
123 #if defined( GLX_USE_TLS )
124 extern GLubyte gl_dispatch_functions_start[];
125 extern GLubyte gl_dispatch_functions_end[];
126 #else
127 extern const GLubyte gl_dispatch_functions_start[];
128 #endif
129
130 #endif /* USE_X86_ASM */
131
132
133 /**
134 * Return dispatch function address for the named static (built-in) function.
135 * Return NULL if function not found.
136 */
137 static _glapi_proc
138 get_static_proc_address(const char *funcName)
139 {
140 const glprocs_table_t * const f = find_entry( funcName );
141 if (f) {
142 #if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
143 return (f->Address == NULL)
144 ? (_glapi_proc) (gl_dispatch_functions_start
145 + (DISPATCH_FUNCTION_SIZE * f->Offset))
146 : f->Address;
147 #elif defined(DISPATCH_FUNCTION_SIZE)
148 return (_glapi_proc) (gl_dispatch_functions_start
149 + (DISPATCH_FUNCTION_SIZE * f->Offset));
150 #else
151 return f->Address;
152 #endif
153 }
154 else {
155 return NULL;
156 }
157 }
158
159 #endif /* !defined(XFree86Server) && !defined(XGLServer) */
160
161
162
163 /**
164 * Return the name of the function at the given offset in the dispatch
165 * table. For debugging only.
166 */
167 static const char *
168 get_static_proc_name( GLuint offset )
169 {
170 GLuint i;
171 for (i = 0; static_functions[i].Name_offset >= 0; i++) {
172 if (static_functions[i].Offset == offset) {
173 return gl_string_table + static_functions[i].Name_offset;
174 }
175 }
176 return NULL;
177 }
178
179
180
181 /**********************************************************************
182 * Extension function management.
183 */
184
185
186 /**
187 * Track information about a function added to the GL API.
188 */
189 struct _glapi_function {
190 /**
191 * Name of the function.
192 */
193 const char * name;
194
195
196 /**
197 * Text string that describes the types of the parameters passed to the
198 * named function. Parameter types are converted to characters using the
199 * following rules:
200 * - 'i' for \c GLint, \c GLuint, and \c GLenum
201 * - 'p' for any pointer type
202 * - 'f' for \c GLfloat and \c GLclampf
203 * - 'd' for \c GLdouble and \c GLclampd
204 */
205 const char * parameter_signature;
206
207
208 /**
209 * Offset in the dispatch table where the pointer to the real function is
210 * located. If the driver has not requested that the named function be
211 * added to the dispatch table, this will have the value ~0.
212 */
213 unsigned dispatch_offset;
214
215
216 /**
217 * Pointer to the dispatch stub for the named function.
218 *
219 * \todo
220 * The semantic of this field should be changed slightly. Currently, it
221 * is always expected to be non-\c NULL. However, it would be better to
222 * only allocate the entry-point stub when the application requests the
223 * function via \c glXGetProcAddress. This would save memory for all the
224 * functions that the driver exports but that the application never wants
225 * to call.
226 */
227 _glapi_proc dispatch_stub;
228 };
229
230
231 static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
232 static GLuint NumExtEntryPoints = 0;
233
234 #ifdef USE_SPARC_ASM
235 extern void __glapi_sparc_icache_flush(unsigned int *);
236 #endif
237
238 /**
239 * Generate a dispatch function (entrypoint) which jumps through
240 * the given slot number (offset) in the current dispatch table.
241 * We need assembly language in order to accomplish this.
242 */
243 static _glapi_proc
244 generate_entrypoint(GLuint functionOffset)
245 {
246 #if defined(USE_X86_ASM)
247 /* 32 is chosen as something of a magic offset. For x86, the dispatch
248 * at offset 32 is the first one where the offset in the
249 * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
250 */
251 const GLubyte * const template_func = gl_dispatch_functions_start
252 + (DISPATCH_FUNCTION_SIZE * 32);
253 GLubyte * const code = (GLubyte *) malloc(DISPATCH_FUNCTION_SIZE);
254
255
256 if ( code != NULL ) {
257 (void) memcpy(code, template_func, DISPATCH_FUNCTION_SIZE);
258 fill_in_entrypoint_offset( (_glapi_proc) code, functionOffset );
259 }
260
261 return (_glapi_proc) code;
262 #elif defined(USE_SPARC_ASM) && (defined(PTHREADS) || defined(GLX_USE_TLS))
263 static const unsigned int template[] = {
264 0x07000000, /* sethi %hi(0), %g3 */
265 0x8210000f, /* mov %o7, %g1 */
266 0x40000000, /* call */
267 0x9e100001, /* mov %g1, %o7 */
268 };
269 #ifdef GLX_USE_TLS
270 extern unsigned int __glapi_sparc_tls_stub;
271 unsigned long call_dest = (unsigned long ) &__glapi_sparc_tls_stub;
272 #else
273 extern unsigned int __glapi_sparc_pthread_stub;
274 unsigned long call_dest = (unsigned long ) &__glapi_sparc_pthread_stub;
275 #endif
276 unsigned int *code = (unsigned int *) malloc(sizeof(template));
277 if (code) {
278 code[0] = template[0] | (functionOffset & 0x3fffff);
279 code[1] = template[1];
280 __glapi_sparc_icache_flush(&code[0]);
281 code[2] = template[2] |
282 (((call_dest - ((unsigned long) &code[2]))
283 >> 2) & 0x3fffffff);
284 code[3] = template[3];
285 __glapi_sparc_icache_flush(&code[2]);
286 }
287 return (_glapi_proc) code;
288 #else
289 (void) functionOffset;
290 return NULL;
291 #endif /* USE_*_ASM */
292 }
293
294
295 /**
296 * This function inserts a new dispatch offset into the assembly language
297 * stub that was generated with the preceeding function.
298 */
299 static void
300 fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset)
301 {
302 #if defined(USE_X86_ASM)
303 GLubyte * const code = (GLubyte *) entrypoint;
304
305 #if DISPATCH_FUNCTION_SIZE == 32
306 *((unsigned int *)(code + 11)) = 4 * offset;
307 *((unsigned int *)(code + 22)) = 4 * offset;
308 #elif DISPATCH_FUNCTION_SIZE == 16 && defined( GLX_USE_TLS )
309 *((unsigned int *)(code + 8)) = 4 * offset;
310 #elif DISPATCH_FUNCTION_SIZE == 16
311 *((unsigned int *)(code + 7)) = 4 * offset;
312 #else
313 # error Invalid DISPATCH_FUNCTION_SIZE!
314 #endif
315
316 #elif defined(USE_SPARC_ASM)
317 unsigned int *code = (unsigned int *) entrypoint;
318 code[0] &= ~0x3fffff;
319 code[0] |= (offset * sizeof(void *)) & 0x3fffff;
320 __glapi_sparc_icache_flush(&code[0]);
321 #else
322
323 /* an unimplemented architecture */
324 (void) entrypoint;
325 (void) offset;
326
327 #endif /* USE_*_ASM */
328 }
329
330
331 /**
332 * Generate new entrypoint
333 *
334 * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver
335 * calls \c _glapi_add_dispatch we'll put in the proper offset. If that
336 * never happens, and the user calls this function, he'll segfault. That's
337 * what you get when you try calling a GL function that doesn't really exist.
338 *
339 * \param funcName Name of the function to create an entry-point for.
340 *
341 * \sa _glapi_add_entrypoint
342 */
343
344 static struct _glapi_function *
345 add_function_name( const char * funcName )
346 {
347 struct _glapi_function * entry = NULL;
348
349 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
350 _glapi_proc entrypoint = generate_entrypoint(~0);
351 if (entrypoint != NULL) {
352 entry = & ExtEntryTable[NumExtEntryPoints];
353
354 ExtEntryTable[NumExtEntryPoints].name = str_dup(funcName);
355 ExtEntryTable[NumExtEntryPoints].parameter_signature = NULL;
356 ExtEntryTable[NumExtEntryPoints].dispatch_offset = ~0;
357 ExtEntryTable[NumExtEntryPoints].dispatch_stub = entrypoint;
358 NumExtEntryPoints++;
359 }
360 }
361
362 return entry;
363 }
364
365
366 /**
367 * Fill-in the dispatch stub for the named function.
368 *
369 * This function is intended to be called by a hardware driver. When called,
370 * a dispatch stub may be created created for the function. A pointer to this
371 * dispatch function will be returned by glXGetProcAddress.
372 *
373 * \param function_names Array of pointers to function names that should
374 * share a common dispatch offset.
375 * \param parameter_signature String representing the types of the parameters
376 * passed to the named function. Parameter types
377 * are converted to characters using the following
378 * rules:
379 * - 'i' for \c GLint, \c GLuint, and \c GLenum
380 * - 'p' for any pointer type
381 * - 'f' for \c GLfloat and \c GLclampf
382 * - 'd' for \c GLdouble and \c GLclampd
383 *
384 * \returns
385 * The offset in the dispatch table of the named function. A pointer to the
386 * driver's implementation of the named function should be stored at
387 * \c dispatch_table[\c offset]. Return -1 if error/problem.
388 *
389 * \sa glXGetProcAddress
390 *
391 * \warning
392 * This function can only handle up to 8 names at a time. As far as I know,
393 * the maximum number of names ever associated with an existing GL function is
394 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
395 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
396 * too painful of a limitation.
397 *
398 * \todo
399 * Determine whether or not \c parameter_signature should be allowed to be
400 * \c NULL. It doesn't seem like much of a hardship for drivers to have to
401 * pass in an empty string.
402 *
403 * \todo
404 * Determine if code should be added to reject function names that start with
405 * 'glX'.
406 *
407 * \bug
408 * Add code to compare \c parameter_signature with the parameter signature of
409 * a static function. In order to do that, we need to find a way to \b get
410 * the parameter signature of a static function.
411 */
412
413 PUBLIC int
414 _glapi_add_dispatch( const char * const * function_names,
415 const char * parameter_signature )
416 {
417 static int next_dynamic_offset = _gloffset_FIRST_DYNAMIC;
418 const char * const real_sig = (parameter_signature != NULL)
419 ? parameter_signature : "";
420 struct _glapi_function * entry[8];
421 GLboolean is_static[8];
422 unsigned i;
423 unsigned j;
424 int offset = ~0;
425 int new_offset;
426
427
428 (void) memset( is_static, 0, sizeof( is_static ) );
429 (void) memset( entry, 0, sizeof( entry ) );
430
431 for ( i = 0 ; function_names[i] != NULL ; i++ ) {
432 /* Do some trivial validation on the name of the function.
433 */
434
435 if (!function_names[i] || function_names[i][0] != 'g' || function_names[i][1] != 'l')
436 return -1;
437
438 /* Determine if the named function already exists. If the function does
439 * exist, it must have the same parameter signature as the function
440 * being added.
441 */
442
443 new_offset = get_static_proc_offset(function_names[i]);
444 if (new_offset >= 0) {
445 /* FIXME: Make sure the parameter signatures match! How do we get
446 * FIXME: the parameter signature for static functions?
447 */
448
449 if ( (offset != ~0) && (new_offset != offset) ) {
450 return -1;
451 }
452
453 is_static[i] = GL_TRUE;
454 offset = new_offset;
455 }
456
457
458 for ( j = 0 ; j < NumExtEntryPoints ; j++ ) {
459 if (strcmp(ExtEntryTable[j].name, function_names[i]) == 0) {
460 /* The offset may be ~0 if the function name was added by
461 * glXGetProcAddress but never filled in by the driver.
462 */
463
464 if (ExtEntryTable[j].dispatch_offset != ~0) {
465 if (strcmp(real_sig, ExtEntryTable[j].parameter_signature)
466 != 0) {
467 return -1;
468 }
469
470 if ( (offset != ~0) && (ExtEntryTable[j].dispatch_offset != offset) ) {
471 return -1;
472 }
473
474 offset = ExtEntryTable[j].dispatch_offset;
475 }
476
477 entry[i] = & ExtEntryTable[j];
478 break;
479 }
480 }
481 }
482
483 if (offset == ~0) {
484 offset = next_dynamic_offset;
485 next_dynamic_offset++;
486 }
487
488 for ( i = 0 ; function_names[i] != NULL ; i++ ) {
489 if (! is_static[i] ) {
490 if (entry[i] == NULL) {
491 entry[i] = add_function_name( function_names[i] );
492 if (entry[i] == NULL) {
493 /* FIXME: Possible memory leak here.
494 */
495 return -1;
496 }
497 }
498
499 entry[i]->parameter_signature = str_dup(real_sig);
500 fill_in_entrypoint_offset(entry[i]->dispatch_stub, offset);
501 entry[i]->dispatch_offset = offset;
502 }
503 }
504
505 return offset;
506 }
507
508
509 /**
510 * Return offset of entrypoint for named function within dispatch table.
511 */
512 PUBLIC GLint
513 _glapi_get_proc_offset(const char *funcName)
514 {
515 /* search extension functions first */
516 GLuint i;
517 for (i = 0; i < NumExtEntryPoints; i++) {
518 if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
519 return ExtEntryTable[i].dispatch_offset;
520 }
521 }
522 /* search static functions */
523 return get_static_proc_offset(funcName);
524 }
525
526
527
528 /**
529 * Return pointer to the named function. If the function name isn't found
530 * in the name of static functions, try generating a new API entrypoint on
531 * the fly with assembly language.
532 */
533 PUBLIC _glapi_proc
534 _glapi_get_proc_address(const char *funcName)
535 {
536 struct _glapi_function * entry;
537 GLuint i;
538
539 #ifdef MANGLE
540 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
541 return NULL;
542 #else
543 if (funcName[0] != 'g' || funcName[1] != 'l')
544 return NULL;
545 #endif
546
547 /* search extension functions first */
548 for (i = 0; i < NumExtEntryPoints; i++) {
549 if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
550 return ExtEntryTable[i].dispatch_stub;
551 }
552 }
553
554 #if !defined( XFree86Server ) && !defined( XGLServer )
555 /* search static functions */
556 {
557 const _glapi_proc func = get_static_proc_address(funcName);
558 if (func)
559 return func;
560 }
561 #endif /* !defined( XFree86Server ) */
562
563 entry = add_function_name(funcName);
564 return (entry == NULL) ? NULL : entry->dispatch_stub;
565 }
566
567
568
569 /**
570 * Return the name of the function at the given dispatch offset.
571 * This is only intended for debugging.
572 */
573 const char *
574 _glapi_get_proc_name(GLuint offset)
575 {
576 GLuint i;
577 const char * n;
578
579 /* search built-in functions */
580 n = get_static_proc_name(offset);
581 if ( n != NULL ) {
582 return n;
583 }
584
585 /* search added extension functions */
586 for (i = 0; i < NumExtEntryPoints; i++) {
587 if (ExtEntryTable[i].dispatch_offset == offset) {
588 return ExtEntryTable[i].name;
589 }
590 }
591 return NULL;
592 }