blob: 2a083949fe0b9d6259dbd7f5236ac8df991ec751 [file] [log] [blame]
Brian Paulfbd8f211999-11-11 01:22:25 +00001
2/*
3 * Mesa 3-D graphics library
Brian Paul5104b4d2002-03-07 21:50:41 +00004 * Version: 4.1
Brian Paulfbd8f211999-11-11 01:22:25 +00005 *
Brian Paul5104b4d2002-03-07 21:50:41 +00006 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
Brian Paulfbd8f211999-11-11 01:22:25 +00007 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
Brian Paul7e1161b1999-11-25 18:17:04 +000027/*
28 * This file manages the OpenGL API dispatch layer.
29 * The dispatch table (struct _glapi_table) is basically just a list
30 * of function pointers.
31 * There are functions to set/get the current dispatch table for the
32 * current thread and to manage registration/dispatch of dynamically
33 * added extension functions.
Brian Paul9f943992000-01-28 19:03:33 +000034 *
35 * It's intended that this file and the other glapi*.[ch] files are
36 * flexible enough to be reused in several places: XFree86, DRI-
37 * based libGL.so, and perhaps the SGI SI.
38 *
Brian Paul4e9676f2002-06-29 19:48:15 +000039 * NOTE: There are no dependencies on Mesa in this code.
Brian Paulab0c8862001-01-23 23:35:47 +000040 *
41 * Versions (API changes):
42 * 2000/02/23 - original version for Mesa 3.3 and XFree86 4.0
43 * 2001/01/16 - added dispatch override feature for Mesa 3.5
Brian Paul4e9676f2002-06-29 19:48:15 +000044 * 2002/06/28 - added _glapi_set_warning_func(), Mesa 4.1.
Brian Paul54f3aab2002-10-02 01:51:44 +000045 * 2002/10/01 - _glapi_get_proc_address() will now generate new entrypoints
46 * itself (using offset ~0). _glapi_add_entrypoint() can be
47 * called afterward and it'll fill in the correct dispatch
48 * offset. This allows DRI libGL to avoid probing for DRI
49 * drivers! No changes to the public glapi interface.
Brian Paul7e1161b1999-11-25 18:17:04 +000050 */
51
52
53
Brian Paul3c27be32000-02-10 21:27:48 +000054#include "glheader.h"
Brian Paulfbd8f211999-11-11 01:22:25 +000055#include "glapi.h"
Brian Paul0c239fc1999-12-16 12:38:11 +000056#include "glapioffsets.h"
57#include "glapitable.h"
Brian Paul9f943992000-01-28 19:03:33 +000058#include "glthread.h"
Brian Paulbb72d321999-12-16 17:31:59 +000059
Brian Paul3c257e12001-03-28 17:19:58 +000060/***** BEGIN NO-OP DISPATCH *****/
61
62static GLboolean WarnFlag = GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000063static _glapi_warning_func warning_func;
Brian Paul3c257e12001-03-28 17:19:58 +000064
Brian Paul4e9676f2002-06-29 19:48:15 +000065
66/*
67 * Enable/disable printing of warning messages.
68 */
Brian Paul3c257e12001-03-28 17:19:58 +000069void
70_glapi_noop_enable_warnings(GLboolean enable)
71{
72 WarnFlag = enable;
73}
74
Brian Paul4e9676f2002-06-29 19:48:15 +000075/*
76 * Register a callback function for reporting errors.
77 */
78void
79_glapi_set_warning_func( _glapi_warning_func func )
80{
81 warning_func = func;
82}
83
Brian Paul3c257e12001-03-28 17:19:58 +000084static GLboolean
85warn(void)
86{
Brian Paul4e9676f2002-06-29 19:48:15 +000087 if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
88 && warning_func) {
Brian Paul3c257e12001-03-28 17:19:58 +000089 return GL_TRUE;
Brian Paul4e9676f2002-06-29 19:48:15 +000090 }
91 else {
Brian Paul3c257e12001-03-28 17:19:58 +000092 return GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000093 }
Brian Paul3c257e12001-03-28 17:19:58 +000094}
95
96
97#define KEYWORD1 static
Daniel Borca722cb892004-01-07 12:37:09 +000098#define KEYWORD2 GLAPIENTRY
Brian Paul3c257e12001-03-28 17:19:58 +000099#define NAME(func) NoOp##func
100
Brian Paul4e9676f2002-06-29 19:48:15 +0000101#define F NULL
Brian Paul3c257e12001-03-28 17:19:58 +0000102
Brian Paul4e9676f2002-06-29 19:48:15 +0000103#define DISPATCH(func, args, msg) \
104 if (warn()) { \
105 warning_func(NULL, "GL User Error: called without context:"); \
106 warning_func msg; \
Brian Paul3c257e12001-03-28 17:19:58 +0000107 }
108
Brian Paul4e9676f2002-06-29 19:48:15 +0000109#define RETURN_DISPATCH(func, args, msg) \
110 if (warn()) { \
111 warning_func(NULL, "GL User Error: called without context:"); \
112 warning_func msg; \
113 } \
Brian Paul3c257e12001-03-28 17:19:58 +0000114 return 0
115
116#define DISPATCH_TABLE_NAME __glapi_noop_table
117#define UNUSED_TABLE_NAME __usused_noop_functions
118
119#define TABLE_ENTRY(name) (void *) NoOp##name
120
121static int NoOpUnused(void)
122{
123 if (warn()) {
Brian Paul4e9676f2002-06-29 19:48:15 +0000124 warning_func(NULL, "GL User Error: calling extension function without a current context\n");
Brian Paul3c257e12001-03-28 17:19:58 +0000125 }
126 return 0;
127}
128
129#include "glapitemp.h"
130
131/***** END NO-OP DISPATCH *****/
132
133
134
135/***** BEGIN THREAD-SAFE DISPATCH *****/
Brian Paul3c257e12001-03-28 17:19:58 +0000136
137#if defined(THREADS)
138
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000139/**
140 * \name Multi-threaded control support variables
141 *
142 * If thread-safety is supported, there are two potential mechanisms that can
143 * be used. The old-style mechanism would set \c _glapi_Dispatch to a special
144 * thread-safe dispatch table. These dispatch routines would call
145 * \c _glapi_get_dispatch to get the actual dispatch pointer. In this
146 * setup \c _glapi_Dispatch could never be \c NULL. This dual layered
147 * dispatch setup performed great for single-threaded apps, but didn't
148 * perform well for multithreaded apps.
149 *
150 * In the new mechansim, there are two variables. The first is
151 * \c _glapi_DispatchTSD. In the single-threaded case, this variable points
152 * to the dispatch table. In the multi-threaded case, this variable is
153 * \c NULL, and thread-specific variable \c _gl_DispatchTSD points to the
154 * actual dispatch table. \c _glapi_DispatchTSD is used to signal to the
155 * static dispatch functions to call \c _glapi_get_dispatch to get the real
156 * dispatch table.
157 *
158 * Throughout the code \c _glapi_DispatchTSD == \c NULL is used to determine
159 * whether or not the application is multi-threaded.
160 */
161/*@{*/
162_glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */
163static _glthread_TSD RealDispatchTSD; /**< only when using override */
164static _glthread_TSD ContextTSD; /**< Per-thread context pointer */
165/*@}*/
Brian Paul3c257e12001-03-28 17:19:58 +0000166
167
Brian Paul3c257e12001-03-28 17:19:58 +0000168#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
169#define UNUSED_TABLE_NAME __usused_threadsafe_functions
170
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000171#define TABLE_ENTRY(name) (void *) gl##name
Brian Paul3c257e12001-03-28 17:19:58 +0000172
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000173static int glUnused(void)
Brian Paul3c257e12001-03-28 17:19:58 +0000174{
175 return 0;
176}
177
178#include "glapitemp.h"
179
180#endif
181
182/***** END THREAD-SAFE DISPATCH *****/
183
184
185
Brian Paul8ceb5c32000-02-24 22:14:04 +0000186struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000187struct _glapi_table *_glapi_DispatchTSD = (struct _glapi_table *) __glapi_noop_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000188struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul0f710251999-12-15 15:02:30 +0000189
Brian Paul8f91fb61999-12-17 14:51:28 +0000190/* Used when thread safety disabled */
Brian Paulf9b97d92000-01-28 20:17:42 +0000191void *_glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000192
Brian Paul0f710251999-12-15 15:02:30 +0000193
Brian Paulab0c8862001-01-23 23:35:47 +0000194static GLboolean DispatchOverride = GL_FALSE;
195
196
Brian Paul54f3aab2002-10-02 01:51:44 +0000197
Brian Paul3c257e12001-03-28 17:19:58 +0000198/* strdup() is actually not a standard ANSI C or POSIX routine.
199 * Irix will not define it if ANSI mode is in effect.
200 */
201static char *
202str_dup(const char *str)
Randy Frankd7361e12000-03-27 21:13:58 +0000203{
Brian Paulfffb8092000-03-29 18:46:11 +0000204 char *copy;
205 copy = (char*) malloc(strlen(str) + 1);
206 if (!copy)
207 return NULL;
208 strcpy(copy, str);
209 return copy;
Randy Frankd7361e12000-03-27 21:13:58 +0000210}
211
Brian Paul7fb54ae1999-11-19 22:33:50 +0000212
Brian Paulbb72d321999-12-16 17:31:59 +0000213
214/*
215 * We should call this periodically from a function such as glXMakeCurrent
Brian Paul5104b4d2002-03-07 21:50:41 +0000216 * in order to test if multiple threads are being used.
Brian Paulbb72d321999-12-16 17:31:59 +0000217 */
218void
219_glapi_check_multithread(void)
220{
221#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000222 if ( _glapi_DispatchTSD != NULL ) {
Brian Paulbb72d321999-12-16 17:31:59 +0000223 static unsigned long knownID;
224 static GLboolean firstCall = GL_TRUE;
225 if (firstCall) {
226 knownID = _glthread_GetID();
227 firstCall = GL_FALSE;
228 }
229 else if (knownID != _glthread_GetID()) {
Brian Paulbb72d321999-12-16 17:31:59 +0000230 _glapi_set_dispatch(NULL);
231 }
232 }
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000233 else if (!_glapi_get_dispatch()) {
234 /* make sure that this thread's dispatch pointer isn't null */
235 _glapi_set_dispatch(NULL);
236 }
Brian Paulbb72d321999-12-16 17:31:59 +0000237#endif
238}
239
240
241
242/*
Brian Paul8f91fb61999-12-17 14:51:28 +0000243 * Set the current context pointer for this thread.
244 * The context pointer is an opaque type which should be cast to
245 * void from the real context pointer type.
246 */
247void
Brian Paulf9b97d92000-01-28 20:17:42 +0000248_glapi_set_context(void *context)
Brian Paul8f91fb61999-12-17 14:51:28 +0000249{
250#if defined(THREADS)
Brian Paul3c27be32000-02-10 21:27:48 +0000251 _glthread_SetTSD(&ContextTSD, context);
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000252 _glapi_Context = (_glapi_DispatchTSD == NULL) ? NULL : context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000253#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000254 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000255#endif
256}
257
258
259
260/*
261 * Get the current context pointer for this thread.
262 * The context pointer is an opaque type which should be cast from
263 * void to the real context pointer type.
264 */
265void *
Brian Paulf9b97d92000-01-28 20:17:42 +0000266_glapi_get_context(void)
Brian Paul8f91fb61999-12-17 14:51:28 +0000267{
268#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000269 if ( _glapi_DispatchTSD == NULL ) {
Brian Paul8f91fb61999-12-17 14:51:28 +0000270 return _glthread_GetTSD(&ContextTSD);
271 }
272 else {
Brian Paulf9b97d92000-01-28 20:17:42 +0000273 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000274 }
275#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000276 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000277#endif
278}
279
280
281
282/*
Brian Paul7fb54ae1999-11-19 22:33:50 +0000283 * Set the global or per-thread dispatch table pointer.
284 */
285void
286_glapi_set_dispatch(struct _glapi_table *dispatch)
287{
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000288 struct _glapi_table * old_style_dispatch;
289
290
291 /* Use the no-op functions if a NULL dispatch table was requested.
292 */
293
Keith Whitwell009aa3e2004-06-30 11:48:21 +0000294 old_style_dispatch = (dispatch == NULL)
295 ? (struct _glapi_table *) __glapi_noop_table : dispatch;
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000296
Brian Paul7fb54ae1999-11-19 22:33:50 +0000297#ifdef DEBUG
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000298 if (dispatch != NULL) {
Brian Paul7fb54ae1999-11-19 22:33:50 +0000299 _glapi_check_table(dispatch);
300 }
301#endif
302
303#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000304 if (DispatchOverride) {
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000305 _glthread_SetTSD(&RealDispatchTSD, (void *) old_style_dispatch);
306 if ( dispatch == NULL )
Brian Paul3c257e12001-03-28 17:19:58 +0000307 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000308 else
Brian Paulab0c8862001-01-23 23:35:47 +0000309 _glapi_RealDispatch = dispatch;
Brian Paul3b18a362000-09-26 15:27:20 +0000310 }
311 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000312 /* normal operation */
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000313 _glthread_SetTSD(&_gl_DispatchTSD, (void *) old_style_dispatch);
314 _glapi_DispatchTSD = dispatch;
315
316 _glapi_Dispatch = (dispatch == NULL)
317 ? (struct _glapi_table *) __glapi_threadsafe_table
318 : old_style_dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000319 }
Brian Paul3a71d052000-09-05 20:17:37 +0000320#else /*THREADS*/
Brian Paulab0c8862001-01-23 23:35:47 +0000321 if (DispatchOverride) {
322 _glapi_RealDispatch = dispatch;
323 }
324 else {
325 _glapi_Dispatch = dispatch;
326 }
Brian Paul3a71d052000-09-05 20:17:37 +0000327#endif /*THREADS*/
Brian Paul7fb54ae1999-11-19 22:33:50 +0000328}
329
330
Brian Paulbb72d321999-12-16 17:31:59 +0000331
Brian Paul7fb54ae1999-11-19 22:33:50 +0000332/*
Brian Paulbb72d321999-12-16 17:31:59 +0000333 * Return pointer to current dispatch table for calling thread.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000334 */
335struct _glapi_table *
336_glapi_get_dispatch(void)
337{
338#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000339 if ( _glapi_DispatchTSD == NULL ) {
Brian Paulab0c8862001-01-23 23:35:47 +0000340 if (DispatchOverride) {
341 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
342 }
343 else {
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000344 return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
Brian Paulab0c8862001-01-23 23:35:47 +0000345 }
Brian Paulbb72d321999-12-16 17:31:59 +0000346 }
Brian Paul590d3471999-12-17 12:20:23 +0000347 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000348 if (DispatchOverride) {
349 assert(_glapi_RealDispatch);
350 return _glapi_RealDispatch;
351 }
352 else {
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000353 assert(_glapi_DispatchTSD);
354 return _glapi_DispatchTSD;
Brian Paulab0c8862001-01-23 23:35:47 +0000355 }
Brian Paul590d3471999-12-17 12:20:23 +0000356 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000357#else
Brian Paulc2319b42000-01-17 19:28:31 +0000358 return _glapi_Dispatch;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000359#endif
360}
361
362
Brian Paulab0c8862001-01-23 23:35:47 +0000363/*
364 * Notes on dispatch overrride:
365 *
366 * Dispatch override allows an external agent to hook into the GL dispatch
367 * mechanism before execution goes into the core rendering library. For
368 * example, a trace mechanism would insert itself as an overrider, print
369 * logging info for each GL function, then dispatch to the real GL function.
370 *
371 * libGLS (GL Stream library) is another agent that might use override.
372 *
373 * We don't allow more than one layer of overriding at this time.
374 * In the future we may allow nested/layered override. In that case
375 * _glapi_begin_dispatch_override() will return an override layer,
376 * _glapi_end_dispatch_override(layer) will remove an override layer
377 * and _glapi_get_override_dispatch(layer) will return the dispatch
378 * table for a given override layer. layer = 0 will be the "real"
379 * dispatch table.
380 */
381
382/*
383 * Return: dispatch override layer number.
384 */
385int
386_glapi_begin_dispatch_override(struct _glapi_table *override)
Brian Paul3a71d052000-09-05 20:17:37 +0000387{
Brian Paulab0c8862001-01-23 23:35:47 +0000388 struct _glapi_table *real = _glapi_get_dispatch();
389
390 assert(!DispatchOverride); /* can't nest at this time */
391 DispatchOverride = GL_TRUE;
392
393 _glapi_set_dispatch(real);
Brian Paul3a71d052000-09-05 20:17:37 +0000394
395#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000396 _glthread_SetTSD(&_gl_DispatchTSD, (void *) override);
397 if ( _glapi_DispatchTSD == NULL ) {
Brian Paul3c257e12001-03-28 17:19:58 +0000398 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000399 }
400 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000401 _glapi_Dispatch = override;
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000402 _glapi_DispatchTSD = override;
403 }
Brian Paulab0c8862001-01-23 23:35:47 +0000404#else
405 _glapi_Dispatch = override;
406#endif
407 return 1;
408}
409
410
411void
412_glapi_end_dispatch_override(int layer)
413{
414 struct _glapi_table *real = _glapi_get_dispatch();
415 (void) layer;
416 DispatchOverride = GL_FALSE;
417 _glapi_set_dispatch(real);
418 /* the rest of this isn't needed, just play it safe */
419#if defined(THREADS)
420 _glthread_SetTSD(&RealDispatchTSD, NULL);
421#endif
422 _glapi_RealDispatch = NULL;
423}
424
425
426struct _glapi_table *
427_glapi_get_override_dispatch(int layer)
428{
429 if (layer == 0) {
430 return _glapi_get_dispatch();
Brian Paul3a71d052000-09-05 20:17:37 +0000431 }
432 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000433 if (DispatchOverride) {
434#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000435 return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
Brian Paul3a71d052000-09-05 20:17:37 +0000436#else
Brian Paulab0c8862001-01-23 23:35:47 +0000437 return _glapi_Dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000438#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000439 }
440 else {
441 return NULL;
442 }
443 }
Brian Paul3a71d052000-09-05 20:17:37 +0000444}
Brian Paulab0c8862001-01-23 23:35:47 +0000445
Brian Paul3a71d052000-09-05 20:17:37 +0000446
Brian Paul959f8022000-03-19 01:10:11 +0000447struct name_address_offset {
448 const char *Name;
449 GLvoid *Address;
450 GLuint Offset;
451};
452
Brian Paul0c239fc1999-12-16 12:38:11 +0000453
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000454#if !defined( USE_X86_ASM )
Ian Romanick78677992004-05-27 00:05:13 +0000455#define NEED_FUNCTION_POINTER
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000456#endif
Ian Romanick78677992004-05-27 00:05:13 +0000457
Brian Paul54f3aab2002-10-02 01:51:44 +0000458/* The code in this file is auto-generated with Python */
Brian Paulb5fd8862001-11-18 22:48:11 +0000459#include "glprocs.h"
Brian Paul7fb54ae1999-11-19 22:33:50 +0000460
Brian Paul959f8022000-03-19 01:10:11 +0000461
Ian Romanick78677992004-05-27 00:05:13 +0000462static const glprocs_table_t *
463find_entry( const char * n )
464{
465 unsigned i;
466
467 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
468 const char * test_name;
469
470 test_name = gl_string_table + static_functions[i].Name_offset;
471 if (strcmp(test_name, n) == 0) {
472 return & static_functions[i];
473 }
474 }
475 return NULL;
476}
477
Brian Paul959f8022000-03-19 01:10:11 +0000478/*
479 * Return dispatch table offset of the named static (built-in) function.
480 * Return -1 if function not found.
481 */
482static GLint
483get_static_proc_offset(const char *funcName)
484{
Ian Romanick78677992004-05-27 00:05:13 +0000485 const glprocs_table_t * const f = find_entry( funcName );
486
487 if ( f != NULL ) {
488 return f->Offset;
Brian Paul959f8022000-03-19 01:10:11 +0000489 }
490 return -1;
491}
492
493
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000494#ifdef USE_X86_ASM
495extern const GLubyte gl_dispatch_functions_start[];
496
497# if defined(PTHREADS)
498# define X86_DISPATCH_FUNCTION_SIZE 32
499# else
500# define X86_DISPATCH_FUNCTION_SIZE 16
501# endif
502
503
504/*
505 * Return dispatch function address the named static (built-in) function.
506 * Return NULL if function not found.
507 */
508static const GLvoid *
509get_static_proc_address(const char *funcName)
510{
511 const glprocs_table_t * const f = find_entry( funcName );
512
513 if ( f != NULL ) {
514 return gl_dispatch_functions_start
515 + (X86_DISPATCH_FUNCTION_SIZE * f->Offset);
516 }
517 else {
518 return NULL;
519 }
520}
521
522#else
523
524
Brian Paul959f8022000-03-19 01:10:11 +0000525/*
526 * Return dispatch function address the named static (built-in) function.
527 * Return NULL if function not found.
528 */
Ian Romanick78677992004-05-27 00:05:13 +0000529static const GLvoid *
Brian Paul959f8022000-03-19 01:10:11 +0000530get_static_proc_address(const char *funcName)
531{
Ian Romanick78677992004-05-27 00:05:13 +0000532 const glprocs_table_t * const f = find_entry( funcName );
533 return ( f != NULL ) ? f->Address : NULL;
534}
535
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000536#endif /* USE_X86_ASM */
537
Ian Romanick78677992004-05-27 00:05:13 +0000538
539static const char *
540get_static_proc_name( GLuint offset )
541{
542 unsigned i;
543
544 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
545 if (static_functions[i].Offset == offset) {
546 return gl_string_table + static_functions[i].Name_offset;
Brian Paul9c7ca852000-10-19 20:13:12 +0000547 }
548 }
549 return NULL;
Brian Paul959f8022000-03-19 01:10:11 +0000550}
551
552
553
554/**********************************************************************
555 * Extension function management.
556 */
557
Brian Paul54f3aab2002-10-02 01:51:44 +0000558/*
559 * Number of extension functions which we can dynamically add at runtime.
560 */
561#define MAX_EXTENSION_FUNCS 300
Brian Paul959f8022000-03-19 01:10:11 +0000562
Brian Paul54f3aab2002-10-02 01:51:44 +0000563
564/*
565 * The disptach table size (number of entries) is the sizeof the
566 * _glapi_table struct plus the number of dynamic entries we can add.
567 * The extra slots can be filled in by DRI drivers that register new extension
568 * functions.
569 */
570#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
571
Brian Paul959f8022000-03-19 01:10:11 +0000572
573static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
574static GLuint NumExtEntryPoints = 0;
575
davem694a497e62001-06-06 22:55:28 +0000576#ifdef USE_SPARC_ASM
577extern void __glapi_sparc_icache_flush(unsigned int *);
578#endif
Brian Paul959f8022000-03-19 01:10:11 +0000579
580/*
581 * Generate a dispatch function (entrypoint) which jumps through
582 * the given slot number (offset) in the current dispatch table.
583 * We need assembly language in order to accomplish this.
584 */
585static void *
586generate_entrypoint(GLuint functionOffset)
587{
588#if defined(USE_X86_ASM)
589 /*
590 * This x86 code contributed by Josh Vanderhoof.
591 *
592 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
593 * 00 01 02 03 04
594 * 5: 85 c0 testl %eax,%eax
595 * 05 06
596 * 7: 74 06 je f <entrypoint+0xf>
597 * 07 08
598 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
599 * 09 0a 0b 0c 0d 0e
600 * f: e8 fc ff ff ff call __glapi_get_dispatch
601 * 0f 10 11 12 13
602 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
603 * 14 15 16 17 18 19
604 */
Brian Paul54f3aab2002-10-02 01:51:44 +0000605 static const unsigned char insn_template[] = {
Brian Paul959f8022000-03-19 01:10:11 +0000606 0xa1, 0x00, 0x00, 0x00, 0x00,
607 0x85, 0xc0,
608 0x74, 0x06,
609 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
610 0xe8, 0x00, 0x00, 0x00, 0x00,
611 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
612 };
Brian Pauldec2a4d2002-10-29 15:03:14 +0000613 unsigned char *code = (unsigned char *) malloc(sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000614 unsigned int next_insn;
615 if (code) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000616 memcpy(code, insn_template, sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000617
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000618 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_DispatchTSD;
Brian Paul959f8022000-03-19 01:10:11 +0000619 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
620 next_insn = (unsigned int)(code + 0x14);
621 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
622 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
623 }
624 return code;
davem69775355a2001-06-05 23:54:00 +0000625#elif defined(USE_SPARC_ASM)
626
Brian Paul9a90cd42003-12-01 22:40:26 +0000627#if defined(__sparc_v9__) && !defined(__linux__)
davem69775355a2001-06-05 23:54:00 +0000628 static const unsigned int insn_template[] = {
629 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
630 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
631 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
632 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
633 0x8528b020, /* sllx %g2, 32, %g2 */
634 0xc2584002, /* ldx [%g1 + %g2], %g1 */
635 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
636 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
637 0xc6584002, /* ldx [%g1 + %g2], %g3 */
638 0x81c0c000, /* jmpl %g3, %g0 */
639 0x01000000 /* nop */
640 };
641#else
642 static const unsigned int insn_template[] = {
643 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
644 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
645 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
646 0x81c0c000, /* jmpl %g3, %g0 */
647 0x01000000 /* nop */
648 };
649#endif
Brian Pauldec2a4d2002-10-29 15:03:14 +0000650 unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
davem69775355a2001-06-05 23:54:00 +0000651 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
652 if (code) {
653 memcpy(code, insn_template, sizeof(insn_template));
654
Brian Paul9a90cd42003-12-01 22:40:26 +0000655#if defined(__sparc_v9__) && !defined(__linux__)
davem69775355a2001-06-05 23:54:00 +0000656 code[0] |= (glapi_addr >> (32 + 10));
657 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
davem694a497e62001-06-06 22:55:28 +0000658 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000659 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
660 code[3] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000661 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000662 code[6] |= ((functionOffset * 8) >> 10);
663 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000664 __glapi_sparc_icache_flush(&code[6]);
davem69775355a2001-06-05 23:54:00 +0000665#else
666 code[0] |= (glapi_addr >> 10);
667 code[1] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000668 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000669 code[2] |= (functionOffset * 4);
davem694a497e62001-06-06 22:55:28 +0000670 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000671#endif
672 }
673 return code;
Brian Paul959f8022000-03-19 01:10:11 +0000674#else
675 return NULL;
Brian Paul54f3aab2002-10-02 01:51:44 +0000676#endif /* USE_*_ASM */
Brian Paul959f8022000-03-19 01:10:11 +0000677}
678
679
Brian Paul54f3aab2002-10-02 01:51:44 +0000680/*
681 * This function inserts a new dispatch offset into the assembly language
682 * stub that was generated with the preceeding function.
683 */
684static void
685fill_in_entrypoint_offset(void *entrypoint, GLuint offset)
686{
687#if defined(USE_X86_ASM)
688
689 unsigned char *code = (unsigned char *) entrypoint;
690 *(unsigned int *)(code + 0x0b) = offset * 4;
691 *(unsigned int *)(code + 0x16) = offset * 4;
692
693#elif defined(USE_SPARC_ASM)
694
695 /* XXX this hasn't been tested! */
696 unsigned int *code = (unsigned int *) entrypoint;
Brian Paul9a90cd42003-12-01 22:40:26 +0000697#if defined(__sparc_v9__) && !defined(__linux__)
Brian Paul54f3aab2002-10-02 01:51:44 +0000698 code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
699 code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
700 code[6] |= ((offset * 8) >> 10);
701 code[7] |= ((offset * 8) & ((1 << 10) - 1));
702 __glapi_sparc_icache_flush(&code[6]);
Brian Paul9a90cd42003-12-01 22:40:26 +0000703#else /* __sparc_v9__ && !linux */
Brian Paul54f3aab2002-10-02 01:51:44 +0000704 code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
Brian Paul944ea202002-10-17 16:29:17 +0000705 code[2] |= (offset * 4);
Brian Paul54f3aab2002-10-02 01:51:44 +0000706 __glapi_sparc_icache_flush(&code[2]);
Brian Paul9a90cd42003-12-01 22:40:26 +0000707#endif /* __sparc_v9__ && !linux */
Brian Paul54f3aab2002-10-02 01:51:44 +0000708
709#endif /* USE_*_ASM */
710}
711
Brian Paul959f8022000-03-19 01:10:11 +0000712
713/*
714 * Add a new extension function entrypoint.
715 * Return: GL_TRUE = success or GL_FALSE = failure
716 */
717GLboolean
718_glapi_add_entrypoint(const char *funcName, GLuint offset)
719{
Brian Paul8ad10762002-10-11 17:41:03 +0000720 /* trivial rejection test */
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000721#ifdef MANGLE
722 if (!funcName || funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
723 return NULL;
724#else
Brian Paul8ad10762002-10-11 17:41:03 +0000725 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
726 return GL_FALSE;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000727#endif
Brian Paul8ad10762002-10-11 17:41:03 +0000728
Brian Paul959f8022000-03-19 01:10:11 +0000729 /* first check if the named function is already statically present */
730 {
731 GLint index = get_static_proc_offset(funcName);
732 if (index >= 0) {
Brian Paulb51b0a82001-03-07 05:06:11 +0000733 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
Brian Paul959f8022000-03-19 01:10:11 +0000734 }
735 }
736
Brian Paul54f3aab2002-10-02 01:51:44 +0000737 /* See if this function has already been dynamically added */
Brian Paul959f8022000-03-19 01:10:11 +0000738 {
Brian Paul959f8022000-03-19 01:10:11 +0000739 GLuint i;
740 for (i = 0; i < NumExtEntryPoints; i++) {
741 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000742 /* function already registered */
Brian Paul959f8022000-03-19 01:10:11 +0000743 if (ExtEntryTable[i].Offset == offset) {
744 return GL_TRUE; /* offsets match */
745 }
Brian Paule4fcea22003-09-19 15:38:15 +0000746 else if (ExtEntryTable[i].Offset == (GLuint) ~0
Brian Paul54f3aab2002-10-02 01:51:44 +0000747 && offset < DISPATCH_TABLE_SIZE) {
748 /* need to patch-up the dispatch code */
Brian Paule4fcea22003-09-19 15:38:15 +0000749 if (offset != (GLuint) ~0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000750 fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
751 ExtEntryTable[i].Offset = offset;
752 }
753 return GL_TRUE;
754 }
Brian Paul959f8022000-03-19 01:10:11 +0000755 else {
756 return GL_FALSE; /* bad offset! */
757 }
758 }
759 }
Brian Paul959f8022000-03-19 01:10:11 +0000760 }
761
Brian Paul8ad10762002-10-11 17:41:03 +0000762 /* This is a new function, try to add it. */
763 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
764 offset >= DISPATCH_TABLE_SIZE) {
765 /* No space left */
766 return GL_FALSE;
767 }
768 else {
769 void *entrypoint = generate_entrypoint(offset);
770 if (!entrypoint)
771 return GL_FALSE; /* couldn't generate assembly */
772
773 /* OK! */
774 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
775 ExtEntryTable[NumExtEntryPoints].Offset = offset;
776 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
777 NumExtEntryPoints++;
778
779 return GL_TRUE; /* success */
780 }
781
782 /* should never get here, silence compiler warnings */
Brian Paul959f8022000-03-19 01:10:11 +0000783 return GL_FALSE;
784}
785
786
Brian Paul959f8022000-03-19 01:10:11 +0000787/*
788 * Return offset of entrypoint for named function within dispatch table.
789 */
790GLint
791_glapi_get_proc_offset(const char *funcName)
792{
793 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000794 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000795 for (i = 0; i < NumExtEntryPoints; i++) {
796 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
797 return ExtEntryTable[i].Offset;
798 }
799 }
800
801 /* search static functions */
802 return get_static_proc_offset(funcName);
803}
804
805
806
807/*
808 * Return entrypoint for named function.
809 */
810const GLvoid *
811_glapi_get_proc_address(const char *funcName)
812{
Brian Paulb51b0a82001-03-07 05:06:11 +0000813 GLuint i;
Brian Paula6ed6f42003-08-27 14:48:16 +0000814
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000815#ifdef MANGLE
816 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
817 return NULL;
818#else
Brian Paula6ed6f42003-08-27 14:48:16 +0000819 if (funcName[0] != 'g' || funcName[1] != 'l')
820 return NULL;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000821#endif
Brian Paula6ed6f42003-08-27 14:48:16 +0000822
823 /* search extension functions first */
Brian Paul959f8022000-03-19 01:10:11 +0000824 for (i = 0; i < NumExtEntryPoints; i++) {
825 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
826 return ExtEntryTable[i].Address;
827 }
828 }
829
830 /* search static functions */
Brian Paul54f3aab2002-10-02 01:51:44 +0000831 {
832 const GLvoid *func = get_static_proc_address(funcName);
833 if (func)
834 return func;
835 }
Brian Paul959f8022000-03-19 01:10:11 +0000836
Brian Paul54f3aab2002-10-02 01:51:44 +0000837 /* generate new entrypoint - use a temporary dispatch offset of
838 * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
839 * we'll put in the proper offset. If that never happens, and the
840 * user calls this function, he'll segfault. That's what you get
841 * when you try calling a GL function that doesn't really exist.
842 */
843 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
844 GLvoid *entrypoint = generate_entrypoint(~0);
845 if (!entrypoint)
846 return GL_FALSE;
847
848 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
849 ExtEntryTable[NumExtEntryPoints].Offset = ~0;
850 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
851 NumExtEntryPoints++;
852
853 return entrypoint;
854 }
855 else {
856 /* no space for new functions! */
857 return NULL;
858 }
859}
Brian Paul959f8022000-03-19 01:10:11 +0000860
861
862
863/*
864 * Return the name of the function at the given dispatch offset.
865 * This is only intended for debugging.
866 */
867const char *
868_glapi_get_proc_name(GLuint offset)
869{
Brian Paul959f8022000-03-19 01:10:11 +0000870 GLuint i;
Ian Romanick78677992004-05-27 00:05:13 +0000871 const char * n;
Brian Paul54f3aab2002-10-02 01:51:44 +0000872
873 /* search built-in functions */
Ian Romanick78677992004-05-27 00:05:13 +0000874 n = get_static_proc_name(offset);
875 if ( n != NULL ) {
876 return n;
Brian Paul959f8022000-03-19 01:10:11 +0000877 }
878
879 /* search added extension functions */
880 for (i = 0; i < NumExtEntryPoints; i++) {
881 if (ExtEntryTable[i].Offset == offset) {
882 return ExtEntryTable[i].Name;
883 }
884 }
885 return NULL;
886}
887
888
889
890/*
Brian Paul54f3aab2002-10-02 01:51:44 +0000891 * Return size of dispatch table struct as number of functions (or
892 * slots).
893 */
894GLuint
895_glapi_get_dispatch_table_size(void)
896{
897 return DISPATCH_TABLE_SIZE;
898}
899
900
901
902/*
903 * Get API dispatcher version string.
904 */
905const char *
906_glapi_get_version(void)
907{
908 return "20021001"; /* YYYYMMDD */
909}
910
911
912
913/*
Brian Paul959f8022000-03-19 01:10:11 +0000914 * Make sure there are no NULL pointers in the given dispatch table.
Brian Paul5104b4d2002-03-07 21:50:41 +0000915 * Intended for debugging purposes.
Brian Paul959f8022000-03-19 01:10:11 +0000916 */
917void
918_glapi_check_table(const struct _glapi_table *table)
919{
Brian Paul5104b4d2002-03-07 21:50:41 +0000920#ifdef DEBUG
Brian Paul959f8022000-03-19 01:10:11 +0000921 const GLuint entries = _glapi_get_dispatch_table_size();
922 const void **tab = (const void **) table;
923 GLuint i;
924 for (i = 1; i < entries; i++) {
925 assert(tab[i]);
926 }
927
Brian Paul959f8022000-03-19 01:10:11 +0000928 /* Do some spot checks to be sure that the dispatch table
929 * slots are assigned correctly.
930 */
931 {
932 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
933 char *BeginFunc = (char*) &table->Begin;
934 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
935 assert(BeginOffset == _gloffset_Begin);
936 assert(BeginOffset == offset);
937 }
938 {
939 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
940 char *viewportFunc = (char*) &table->Viewport;
941 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
942 assert(viewportOffset == _gloffset_Viewport);
943 assert(viewportOffset == offset);
944 }
945 {
946 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
947 char *VertexPointerFunc = (char*) &table->VertexPointer;
948 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
949 assert(VertexPointerOffset == _gloffset_VertexPointer);
950 assert(VertexPointerOffset == offset);
951 }
952 {
953 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
954 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
955 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
956 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
957 assert(ResetMinMaxOffset == offset);
958 }
959 {
960 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
961 char *blendColorFunc = (char*) &table->BlendColor;
962 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
963 assert(blendColorOffset == _gloffset_BlendColor);
964 assert(blendColorOffset == offset);
965 }
966 {
967 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
968 char *istextureFunc = (char*) &table->IsTextureEXT;
969 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
970 assert(istextureOffset == _gloffset_IsTextureEXT);
971 assert(istextureOffset == offset);
972 }
Brian Paula14cbff2000-10-27 18:31:21 +0000973 {
974 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
975 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
976 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
977 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
978 assert(secondaryColor3fOffset == offset);
979 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
980 }
Brian Paul91d6f122002-05-29 15:23:16 +0000981 {
982 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
983 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
984 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
985 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
986 assert(pointParameterivOffset == offset);
987 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
988 }
Brian Paul54f3aab2002-10-02 01:51:44 +0000989 {
990 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
991 char *setFenceFunc = (char*) &table->SetFenceNV;
992 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
993 assert(setFenceOffset == _gloffset_SetFenceNV);
994 assert(setFenceOffset == offset);
995 assert(_glapi_get_proc_address("glSetFenceNV") == (void *) &glSetFenceNV);
996 }
Brian Paul959f8022000-03-19 01:10:11 +0000997#endif
998}