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