blob: 3c72c3873d3a0518bfece73f32903db6641435a5 [file] [log] [blame]
Brian Paulfbd8f211999-11-11 01:22:25 +00001/*
2 * Mesa 3-D graphics library
Brian Paul767e15a2004-11-27 03:51:11 +00003 * Version: 6.3
Brian Paulfbd8f211999-11-11 01:22:25 +00004 *
Brian Paul767e15a2004-11-27 03:51:11 +00005 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
Brian Paulfbd8f211999-11-11 01:22:25 +00006 *
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
Brian Paul7e1161b1999-11-25 18:17:04 +000026/*
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.
Brian Paul9f943992000-01-28 19:03:33 +000033 *
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 *
Brian Paul4e9676f2002-06-29 19:48:15 +000038 * NOTE: There are no dependencies on Mesa in this code.
Brian Paulab0c8862001-01-23 23:35:47 +000039 *
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
Brian Paul4e9676f2002-06-29 19:48:15 +000043 * 2002/06/28 - added _glapi_set_warning_func(), Mesa 4.1.
Brian Paul54f3aab2002-10-02 01:51:44 +000044 * 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.
Brian Paul7e1161b1999-11-25 18:17:04 +000049 */
50
51
52
Brian Paul3c27be32000-02-10 21:27:48 +000053#include "glheader.h"
Brian Paulfbd8f211999-11-11 01:22:25 +000054#include "glapi.h"
Brian Paul0c239fc1999-12-16 12:38:11 +000055#include "glapioffsets.h"
56#include "glapitable.h"
Brian Paul9f943992000-01-28 19:03:33 +000057#include "glthread.h"
Brian Paulbb72d321999-12-16 17:31:59 +000058
Brian Paul3c257e12001-03-28 17:19:58 +000059/***** BEGIN NO-OP DISPATCH *****/
60
61static GLboolean WarnFlag = GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000062static _glapi_warning_func warning_func;
Brian Paul3c257e12001-03-28 17:19:58 +000063
Brian Paul4e9676f2002-06-29 19:48:15 +000064
65/*
66 * Enable/disable printing of warning messages.
67 */
Brian Paul3c257e12001-03-28 17:19:58 +000068void
69_glapi_noop_enable_warnings(GLboolean enable)
70{
71 WarnFlag = enable;
72}
73
Brian Paul4e9676f2002-06-29 19:48:15 +000074/*
75 * Register a callback function for reporting errors.
76 */
77void
78_glapi_set_warning_func( _glapi_warning_func func )
79{
80 warning_func = func;
81}
82
Brian Paul3c257e12001-03-28 17:19:58 +000083static GLboolean
84warn(void)
85{
Brian Paul4e9676f2002-06-29 19:48:15 +000086 if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
87 && warning_func) {
Brian Paul3c257e12001-03-28 17:19:58 +000088 return GL_TRUE;
Brian Paul4e9676f2002-06-29 19:48:15 +000089 }
90 else {
Brian Paul3c257e12001-03-28 17:19:58 +000091 return GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000092 }
Brian Paul3c257e12001-03-28 17:19:58 +000093}
94
95
96#define KEYWORD1 static
Daniel Borca722cb892004-01-07 12:37:09 +000097#define KEYWORD2 GLAPIENTRY
Brian Paul3c257e12001-03-28 17:19:58 +000098#define NAME(func) NoOp##func
99
Brian Paul4e9676f2002-06-29 19:48:15 +0000100#define F NULL
Brian Paul3c257e12001-03-28 17:19:58 +0000101
Brian Paul5849e3d2004-11-05 18:32:02 +0000102#define DISPATCH(func, args, msg) \
103 if (warn()) { \
104 warning_func(NULL, "GL User Error: called without context: %s", #func); \
Brian Paul3c257e12001-03-28 17:19:58 +0000105 }
106
Brian Paul5849e3d2004-11-05 18:32:02 +0000107#define RETURN_DISPATCH(func, args, msg) \
108 if (warn()) { \
109 warning_func(NULL, "GL User Error: called without context: %s", #func); \
110 } \
Brian Paul3c257e12001-03-28 17:19:58 +0000111 return 0
112
113#define DISPATCH_TABLE_NAME __glapi_noop_table
Brian Paul767e15a2004-11-27 03:51:11 +0000114#define UNUSED_TABLE_NAME __unused_noop_functions
Brian Paul3c257e12001-03-28 17:19:58 +0000115
Brian Paul767e15a2004-11-27 03:51:11 +0000116#define TABLE_ENTRY(name) (_glapi_proc) NoOp##name
Brian Paul3c257e12001-03-28 17:19:58 +0000117
118static int NoOpUnused(void)
119{
120 if (warn()) {
Brian Paul4e9676f2002-06-29 19:48:15 +0000121 warning_func(NULL, "GL User Error: calling extension function without a current context\n");
Brian Paul3c257e12001-03-28 17:19:58 +0000122 }
123 return 0;
124}
125
126#include "glapitemp.h"
127
128/***** END NO-OP DISPATCH *****/
129
130
131
132/***** BEGIN THREAD-SAFE DISPATCH *****/
Brian Paul3c257e12001-03-28 17:19:58 +0000133
134#if defined(THREADS)
135
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000136/**
137 * \name Multi-threaded control support variables
138 *
139 * If thread-safety is supported, there are two potential mechanisms that can
140 * be used. The old-style mechanism would set \c _glapi_Dispatch to a special
141 * thread-safe dispatch table. These dispatch routines would call
142 * \c _glapi_get_dispatch to get the actual dispatch pointer. In this
143 * setup \c _glapi_Dispatch could never be \c NULL. This dual layered
144 * dispatch setup performed great for single-threaded apps, but didn't
145 * perform well for multithreaded apps.
146 *
147 * In the new mechansim, there are two variables. The first is
148 * \c _glapi_DispatchTSD. In the single-threaded case, this variable points
149 * to the dispatch table. In the multi-threaded case, this variable is
150 * \c NULL, and thread-specific variable \c _gl_DispatchTSD points to the
151 * actual dispatch table. \c _glapi_DispatchTSD is used to signal to the
152 * static dispatch functions to call \c _glapi_get_dispatch to get the real
153 * dispatch table.
154 *
Ian Romanickd14d1032004-07-02 00:01:09 +0000155 * There is a race condition in setting \c _glapi_DispatchTSD to \c NULL.
156 * It is possible for the original thread to be setting it at the same instant
157 * a new thread, perhaps running on a different processor, is clearing it.
158 * Because of that, \c ThreadSafe, which can only ever be changed to
Ian Romanick10b3bf62004-07-05 22:42:14 +0000159 * \c GL_TRUE, is used to determine whether or not the application is
Ian Romanickd14d1032004-07-02 00:01:09 +0000160 * multithreaded.
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000161 */
162/*@{*/
Ian Romanickd14d1032004-07-02 00:01:09 +0000163static GLboolean ThreadSafe = GL_FALSE; /**< In thread-safe mode? */
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000164_glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */
165static _glthread_TSD RealDispatchTSD; /**< only when using override */
166static _glthread_TSD ContextTSD; /**< Per-thread context pointer */
167/*@}*/
Brian Paul3c257e12001-03-28 17:19:58 +0000168
169
Brian Paul3c257e12001-03-28 17:19:58 +0000170#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
Brian Paul767e15a2004-11-27 03:51:11 +0000171#define UNUSED_TABLE_NAME __unused_threadsafe_functions
Brian Paul3c257e12001-03-28 17:19:58 +0000172
Brian Paul767e15a2004-11-27 03:51:11 +0000173#define TABLE_ENTRY(name) (_glapi_proc) gl##name
Brian Paul3c257e12001-03-28 17:19:58 +0000174
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000175static int glUnused(void)
Brian Paul3c257e12001-03-28 17:19:58 +0000176{
177 return 0;
178}
179
180#include "glapitemp.h"
181
182#endif
183
184/***** END THREAD-SAFE DISPATCH *****/
185
186
187
Brian Paul8ceb5c32000-02-24 22:14:04 +0000188struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
Ian Romanickd14d1032004-07-02 00:01:09 +0000189#if defined( THREADS )
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000190struct _glapi_table *_glapi_DispatchTSD = (struct _glapi_table *) __glapi_noop_table;
Ian Romanickd14d1032004-07-02 00:01:09 +0000191#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000192struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul0f710251999-12-15 15:02:30 +0000193
Ian Romanickd14d1032004-07-02 00:01:09 +0000194
Brian Paul8f91fb61999-12-17 14:51:28 +0000195/* Used when thread safety disabled */
Brian Paulf9b97d92000-01-28 20:17:42 +0000196void *_glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000197
Brian Paul0f710251999-12-15 15:02:30 +0000198
Brian Paulab0c8862001-01-23 23:35:47 +0000199static GLboolean DispatchOverride = GL_FALSE;
200
201
Brian Paul54f3aab2002-10-02 01:51:44 +0000202
Brian Paul767e15a2004-11-27 03:51:11 +0000203/**
204 * strdup() is actually not a standard ANSI C or POSIX routine.
Brian Paul3c257e12001-03-28 17:19:58 +0000205 * Irix will not define it if ANSI mode is in effect.
206 */
207static char *
208str_dup(const char *str)
Randy Frankd7361e12000-03-27 21:13:58 +0000209{
Brian Paulfffb8092000-03-29 18:46:11 +0000210 char *copy;
211 copy = (char*) malloc(strlen(str) + 1);
212 if (!copy)
213 return NULL;
214 strcpy(copy, str);
215 return copy;
Randy Frankd7361e12000-03-27 21:13:58 +0000216}
217
Brian Paul7fb54ae1999-11-19 22:33:50 +0000218
Brian Paulbb72d321999-12-16 17:31:59 +0000219
Brian Paul767e15a2004-11-27 03:51:11 +0000220/**
Brian Paulbb72d321999-12-16 17:31:59 +0000221 * We should call this periodically from a function such as glXMakeCurrent
Brian Paul5104b4d2002-03-07 21:50:41 +0000222 * in order to test if multiple threads are being used.
Brian Paulbb72d321999-12-16 17:31:59 +0000223 */
224void
225_glapi_check_multithread(void)
226{
227#if defined(THREADS)
Ian Romanickd14d1032004-07-02 00:01:09 +0000228 if (!ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000229 static unsigned long knownID;
230 static GLboolean firstCall = GL_TRUE;
231 if (firstCall) {
232 knownID = _glthread_GetID();
233 firstCall = GL_FALSE;
234 }
235 else if (knownID != _glthread_GetID()) {
Ian Romanickd14d1032004-07-02 00:01:09 +0000236 ThreadSafe = GL_TRUE;
Brian Paulbb72d321999-12-16 17:31:59 +0000237 _glapi_set_dispatch(NULL);
238 }
239 }
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000240 else if (!_glapi_get_dispatch()) {
241 /* make sure that this thread's dispatch pointer isn't null */
242 _glapi_set_dispatch(NULL);
243 }
Brian Paulbb72d321999-12-16 17:31:59 +0000244#endif
245}
246
247
248
Brian Paul767e15a2004-11-27 03:51:11 +0000249/**
Brian Paul8f91fb61999-12-17 14:51:28 +0000250 * Set the current context pointer for this thread.
251 * The context pointer is an opaque type which should be cast to
252 * void from the real context pointer type.
253 */
254void
Brian Paulf9b97d92000-01-28 20:17:42 +0000255_glapi_set_context(void *context)
Brian Paul8f91fb61999-12-17 14:51:28 +0000256{
Brian Paul767e15a2004-11-27 03:51:11 +0000257 (void) __unused_noop_functions; /* silence a warning */
Brian Paul8f91fb61999-12-17 14:51:28 +0000258#if defined(THREADS)
Brian Paul767e15a2004-11-27 03:51:11 +0000259 (void) __unused_threadsafe_functions; /* silence a warning */
Brian Paul3c27be32000-02-10 21:27:48 +0000260 _glthread_SetTSD(&ContextTSD, context);
Ian Romanickd14d1032004-07-02 00:01:09 +0000261 _glapi_Context = (ThreadSafe) ? NULL : context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000262#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000263 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000264#endif
265}
266
267
268
Brian Paul767e15a2004-11-27 03:51:11 +0000269/**
Brian Paul8f91fb61999-12-17 14:51:28 +0000270 * Get the current context pointer for this thread.
271 * The context pointer is an opaque type which should be cast from
272 * void to the real context pointer type.
273 */
274void *
Brian Paulf9b97d92000-01-28 20:17:42 +0000275_glapi_get_context(void)
Brian Paul8f91fb61999-12-17 14:51:28 +0000276{
277#if defined(THREADS)
Ian Romanickd14d1032004-07-02 00:01:09 +0000278 if (ThreadSafe) {
Brian Paul8f91fb61999-12-17 14:51:28 +0000279 return _glthread_GetTSD(&ContextTSD);
280 }
281 else {
Brian Paulf9b97d92000-01-28 20:17:42 +0000282 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000283 }
284#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000285 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000286#endif
287}
288
289
290
Brian Paul767e15a2004-11-27 03:51:11 +0000291/**
Brian Paul7fb54ae1999-11-19 22:33:50 +0000292 * Set the global or per-thread dispatch table pointer.
293 */
294void
295_glapi_set_dispatch(struct _glapi_table *dispatch)
296{
Ian Romanick6c5402b2004-07-05 22:40:54 +0000297 if (!dispatch) {
298 /* use the no-op functions */
299 dispatch = (struct _glapi_table *) __glapi_noop_table;
300 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000301#ifdef DEBUG
Ian Romanick6c5402b2004-07-05 22:40:54 +0000302 else {
Brian Paul7fb54ae1999-11-19 22:33:50 +0000303 _glapi_check_table(dispatch);
304 }
305#endif
306
307#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000308 if (DispatchOverride) {
Ian Romanick6c5402b2004-07-05 22:40:54 +0000309 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
Ian Romanickd14d1032004-07-02 00:01:09 +0000310 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000311 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000312 else
Brian Paulab0c8862001-01-23 23:35:47 +0000313 _glapi_RealDispatch = dispatch;
Brian Paul3b18a362000-09-26 15:27:20 +0000314 }
315 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000316 /* normal operation */
Ian Romanick6c5402b2004-07-05 22:40:54 +0000317 _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
Ian Romanickd14d1032004-07-02 00:01:09 +0000318 if (ThreadSafe) {
319 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
320 _glapi_DispatchTSD = NULL;
321 }
322 else {
Ian Romanick6c5402b2004-07-05 22:40:54 +0000323 _glapi_Dispatch = dispatch;
Ian Romanickd14d1032004-07-02 00:01:09 +0000324 _glapi_DispatchTSD = dispatch;
325 }
Brian Paul3a71d052000-09-05 20:17:37 +0000326 }
Brian Paul3a71d052000-09-05 20:17:37 +0000327#else /*THREADS*/
Brian Paulab0c8862001-01-23 23:35:47 +0000328 if (DispatchOverride) {
329 _glapi_RealDispatch = dispatch;
330 }
331 else {
332 _glapi_Dispatch = dispatch;
333 }
Brian Paul3a71d052000-09-05 20:17:37 +0000334#endif /*THREADS*/
Brian Paul7fb54ae1999-11-19 22:33:50 +0000335}
336
337
Brian Paulbb72d321999-12-16 17:31:59 +0000338
Brian Paul767e15a2004-11-27 03:51:11 +0000339/**
Brian Paulbb72d321999-12-16 17:31:59 +0000340 * Return pointer to current dispatch table for calling thread.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000341 */
342struct _glapi_table *
343_glapi_get_dispatch(void)
344{
345#if defined(THREADS)
Ian Romanickd14d1032004-07-02 00:01:09 +0000346 if (ThreadSafe) {
Brian Paulab0c8862001-01-23 23:35:47 +0000347 if (DispatchOverride) {
348 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
349 }
350 else {
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000351 return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
Brian Paulab0c8862001-01-23 23:35:47 +0000352 }
Brian Paulbb72d321999-12-16 17:31:59 +0000353 }
Brian Paul590d3471999-12-17 12:20:23 +0000354 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000355 if (DispatchOverride) {
356 assert(_glapi_RealDispatch);
357 return _glapi_RealDispatch;
358 }
359 else {
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000360 assert(_glapi_DispatchTSD);
361 return _glapi_DispatchTSD;
Brian Paulab0c8862001-01-23 23:35:47 +0000362 }
Brian Paul590d3471999-12-17 12:20:23 +0000363 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000364#else
Brian Paulc2319b42000-01-17 19:28:31 +0000365 return _glapi_Dispatch;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000366#endif
367}
368
369
Brian Paulab0c8862001-01-23 23:35:47 +0000370/*
371 * Notes on dispatch overrride:
372 *
373 * Dispatch override allows an external agent to hook into the GL dispatch
374 * mechanism before execution goes into the core rendering library. For
375 * example, a trace mechanism would insert itself as an overrider, print
376 * logging info for each GL function, then dispatch to the real GL function.
377 *
378 * libGLS (GL Stream library) is another agent that might use override.
379 *
380 * We don't allow more than one layer of overriding at this time.
381 * In the future we may allow nested/layered override. In that case
382 * _glapi_begin_dispatch_override() will return an override layer,
383 * _glapi_end_dispatch_override(layer) will remove an override layer
384 * and _glapi_get_override_dispatch(layer) will return the dispatch
385 * table for a given override layer. layer = 0 will be the "real"
386 * dispatch table.
387 */
388
389/*
390 * Return: dispatch override layer number.
391 */
392int
393_glapi_begin_dispatch_override(struct _glapi_table *override)
Brian Paul3a71d052000-09-05 20:17:37 +0000394{
Brian Paulab0c8862001-01-23 23:35:47 +0000395 struct _glapi_table *real = _glapi_get_dispatch();
396
397 assert(!DispatchOverride); /* can't nest at this time */
398 DispatchOverride = GL_TRUE;
399
400 _glapi_set_dispatch(real);
Brian Paul3a71d052000-09-05 20:17:37 +0000401
402#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000403 _glthread_SetTSD(&_gl_DispatchTSD, (void *) override);
Ian Romanickd14d1032004-07-02 00:01:09 +0000404 if ( ThreadSafe ) {
Brian Paul3c257e12001-03-28 17:19:58 +0000405 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Ian Romanickd14d1032004-07-02 00:01:09 +0000406 _glapi_DispatchTSD = NULL;
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000407 }
408 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000409 _glapi_Dispatch = override;
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000410 _glapi_DispatchTSD = override;
411 }
Brian Paulab0c8862001-01-23 23:35:47 +0000412#else
413 _glapi_Dispatch = override;
414#endif
415 return 1;
416}
417
418
419void
420_glapi_end_dispatch_override(int layer)
421{
422 struct _glapi_table *real = _glapi_get_dispatch();
423 (void) layer;
424 DispatchOverride = GL_FALSE;
425 _glapi_set_dispatch(real);
426 /* the rest of this isn't needed, just play it safe */
427#if defined(THREADS)
428 _glthread_SetTSD(&RealDispatchTSD, NULL);
429#endif
430 _glapi_RealDispatch = NULL;
431}
432
433
434struct _glapi_table *
435_glapi_get_override_dispatch(int layer)
436{
437 if (layer == 0) {
438 return _glapi_get_dispatch();
Brian Paul3a71d052000-09-05 20:17:37 +0000439 }
440 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000441 if (DispatchOverride) {
442#if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000443 return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
Brian Paul3a71d052000-09-05 20:17:37 +0000444#else
Brian Paulab0c8862001-01-23 23:35:47 +0000445 return _glapi_Dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000446#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000447 }
448 else {
449 return NULL;
450 }
451 }
Brian Paul3a71d052000-09-05 20:17:37 +0000452}
Brian Paulab0c8862001-01-23 23:35:47 +0000453
Brian Paul3a71d052000-09-05 20:17:37 +0000454
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000455#if !defined( USE_X86_ASM )
Ian Romanick78677992004-05-27 00:05:13 +0000456#define NEED_FUNCTION_POINTER
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000457#endif
Ian Romanick78677992004-05-27 00:05:13 +0000458
Brian Paul54f3aab2002-10-02 01:51:44 +0000459/* The code in this file is auto-generated with Python */
Brian Paulb5fd8862001-11-18 22:48:11 +0000460#include "glprocs.h"
Brian Paul7fb54ae1999-11-19 22:33:50 +0000461
Brian Paul959f8022000-03-19 01:10:11 +0000462
Brian Paul767e15a2004-11-27 03:51:11 +0000463/**
464 * Search the table of static entrypoint functions for the named function
465 * and return the corresponding glprocs_table_t entry.
466 */
Ian Romanick78677992004-05-27 00:05:13 +0000467static const glprocs_table_t *
468find_entry( const char * n )
469{
470 unsigned i;
471
472 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
473 const char * test_name;
474
475 test_name = gl_string_table + static_functions[i].Name_offset;
476 if (strcmp(test_name, n) == 0) {
477 return & static_functions[i];
478 }
479 }
480 return NULL;
481}
482
Brian Paul767e15a2004-11-27 03:51:11 +0000483
484/**
Brian Paul959f8022000-03-19 01:10:11 +0000485 * Return dispatch table offset of the named static (built-in) function.
486 * Return -1 if function not found.
487 */
488static GLint
489get_static_proc_offset(const char *funcName)
490{
Ian Romanick78677992004-05-27 00:05:13 +0000491 const glprocs_table_t * const f = find_entry( funcName );
492
493 if ( f != NULL ) {
494 return f->Offset;
Brian Paul959f8022000-03-19 01:10:11 +0000495 }
496 return -1;
497}
498
499
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000500#ifdef USE_X86_ASM
501extern const GLubyte gl_dispatch_functions_start[];
502
Roland Scheideggerd2dbb252004-07-06 00:32:03 +0000503# if defined(THREADS)
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000504# define X86_DISPATCH_FUNCTION_SIZE 32
505# else
506# define X86_DISPATCH_FUNCTION_SIZE 16
507# endif
508
509
Brian Paul767e15a2004-11-27 03:51:11 +0000510/**
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000511 * Return dispatch function address the named static (built-in) function.
512 * Return NULL if function not found.
513 */
514static const GLvoid *
515get_static_proc_address(const char *funcName)
516{
517 const glprocs_table_t * const f = find_entry( funcName );
518
519 if ( f != NULL ) {
520 return gl_dispatch_functions_start
521 + (X86_DISPATCH_FUNCTION_SIZE * f->Offset);
522 }
523 else {
524 return NULL;
525 }
526}
527
528#else
529
530
Brian Paul767e15a2004-11-27 03:51:11 +0000531/**
532 * Return pointer to the named static (built-in) function.
533 * \return NULL if function not found.
Brian Paul959f8022000-03-19 01:10:11 +0000534 */
Brian Paul767e15a2004-11-27 03:51:11 +0000535static const _glapi_proc
Brian Paul959f8022000-03-19 01:10:11 +0000536get_static_proc_address(const char *funcName)
537{
Ian Romanick78677992004-05-27 00:05:13 +0000538 const glprocs_table_t * const f = find_entry( funcName );
539 return ( f != NULL ) ? f->Address : NULL;
540}
541
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000542#endif /* USE_X86_ASM */
543
Ian Romanick78677992004-05-27 00:05:13 +0000544
Brian Paul767e15a2004-11-27 03:51:11 +0000545/**
546 * Return the name of the function at the given offset in the dispatch
547 * table. For debugging only.
548 */
Ian Romanick78677992004-05-27 00:05:13 +0000549static const char *
550get_static_proc_name( GLuint offset )
551{
552 unsigned i;
553
554 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
555 if (static_functions[i].Offset == offset) {
556 return gl_string_table + static_functions[i].Name_offset;
Brian Paul9c7ca852000-10-19 20:13:12 +0000557 }
558 }
559 return NULL;
Brian Paul959f8022000-03-19 01:10:11 +0000560}
561
562
563
564/**********************************************************************
565 * Extension function management.
566 */
567
Brian Paul54f3aab2002-10-02 01:51:44 +0000568/*
569 * Number of extension functions which we can dynamically add at runtime.
570 */
571#define MAX_EXTENSION_FUNCS 300
Brian Paul959f8022000-03-19 01:10:11 +0000572
Brian Paul54f3aab2002-10-02 01:51:44 +0000573
574/*
Brian Paul767e15a2004-11-27 03:51:11 +0000575 * The dispatch table size (number of entries) is the size of the
Brian Paul54f3aab2002-10-02 01:51:44 +0000576 * _glapi_table struct plus the number of dynamic entries we can add.
577 * The extra slots can be filled in by DRI drivers that register new extension
578 * functions.
579 */
580#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
581
Brian Paul959f8022000-03-19 01:10:11 +0000582
Brian Paul767e15a2004-11-27 03:51:11 +0000583struct name_address_offset {
584 const char *Name;
585 _glapi_proc Address;
586 GLuint Offset;
587};
588
589
Brian Paul959f8022000-03-19 01:10:11 +0000590static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
591static GLuint NumExtEntryPoints = 0;
592
davem694a497e62001-06-06 22:55:28 +0000593#ifdef USE_SPARC_ASM
594extern void __glapi_sparc_icache_flush(unsigned int *);
595#endif
Brian Paul959f8022000-03-19 01:10:11 +0000596
Brian Paul767e15a2004-11-27 03:51:11 +0000597/**
Brian Paul959f8022000-03-19 01:10:11 +0000598 * Generate a dispatch function (entrypoint) which jumps through
599 * the given slot number (offset) in the current dispatch table.
600 * We need assembly language in order to accomplish this.
601 */
Brian Paul767e15a2004-11-27 03:51:11 +0000602static _glapi_proc
Brian Paul959f8022000-03-19 01:10:11 +0000603generate_entrypoint(GLuint functionOffset)
604{
605#if defined(USE_X86_ASM)
606 /*
607 * This x86 code contributed by Josh Vanderhoof.
608 *
609 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
610 * 00 01 02 03 04
611 * 5: 85 c0 testl %eax,%eax
612 * 05 06
613 * 7: 74 06 je f <entrypoint+0xf>
614 * 07 08
615 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
616 * 09 0a 0b 0c 0d 0e
617 * f: e8 fc ff ff ff call __glapi_get_dispatch
618 * 0f 10 11 12 13
619 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
620 * 14 15 16 17 18 19
621 */
Brian Paul54f3aab2002-10-02 01:51:44 +0000622 static const unsigned char insn_template[] = {
Brian Paul959f8022000-03-19 01:10:11 +0000623 0xa1, 0x00, 0x00, 0x00, 0x00,
624 0x85, 0xc0,
625 0x74, 0x06,
626 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
627 0xe8, 0x00, 0x00, 0x00, 0x00,
628 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
629 };
Brian Pauldec2a4d2002-10-29 15:03:14 +0000630 unsigned char *code = (unsigned char *) malloc(sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000631 unsigned int next_insn;
632 if (code) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000633 memcpy(code, insn_template, sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000634
Daniel Borcafd003822004-07-05 06:15:37 +0000635#if defined( THREADS )
Ian Romanick8e77da1c2004-06-29 19:08:20 +0000636 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_DispatchTSD;
Daniel Borcafd003822004-07-05 06:15:37 +0000637#else
638 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
639#endif
Brian Paul959f8022000-03-19 01:10:11 +0000640 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
641 next_insn = (unsigned int)(code + 0x14);
642 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
643 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
644 }
Brian Paul767e15a2004-11-27 03:51:11 +0000645 return (_glapi_proc) code;
davem69775355a2001-06-05 23:54:00 +0000646#elif defined(USE_SPARC_ASM)
647
Brian Paulc247c7f2004-11-22 19:27:40 +0000648#if (defined(__sparc_v9__) && (!defined(__linux__) || defined(__linux_sparc_64__)))
davem69775355a2001-06-05 23:54:00 +0000649 static const unsigned int insn_template[] = {
650 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
651 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
652 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
653 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
654 0x8528b020, /* sllx %g2, 32, %g2 */
655 0xc2584002, /* ldx [%g1 + %g2], %g1 */
656 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
657 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
658 0xc6584002, /* ldx [%g1 + %g2], %g3 */
659 0x81c0c000, /* jmpl %g3, %g0 */
660 0x01000000 /* nop */
661 };
662#else
663 static const unsigned int insn_template[] = {
664 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
665 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
666 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
667 0x81c0c000, /* jmpl %g3, %g0 */
668 0x01000000 /* nop */
669 };
670#endif
Brian Pauldec2a4d2002-10-29 15:03:14 +0000671 unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
davem69775355a2001-06-05 23:54:00 +0000672 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
673 if (code) {
674 memcpy(code, insn_template, sizeof(insn_template));
675
Brian Paulc247c7f2004-11-22 19:27:40 +0000676#if (defined(__sparc_v9__) && (!defined(__linux__) || defined(__linux_sparc_64__)))
davem69775355a2001-06-05 23:54:00 +0000677 code[0] |= (glapi_addr >> (32 + 10));
678 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
davem694a497e62001-06-06 22:55:28 +0000679 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000680 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
681 code[3] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000682 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000683 code[6] |= ((functionOffset * 8) >> 10);
684 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000685 __glapi_sparc_icache_flush(&code[6]);
davem69775355a2001-06-05 23:54:00 +0000686#else
687 code[0] |= (glapi_addr >> 10);
688 code[1] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000689 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000690 code[2] |= (functionOffset * 4);
davem694a497e62001-06-06 22:55:28 +0000691 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000692#endif
693 }
Brian Paul767e15a2004-11-27 03:51:11 +0000694 return (_glapi_proc) code;
Brian Paul959f8022000-03-19 01:10:11 +0000695#else
Brian Paula6c423d2004-08-25 15:59:48 +0000696 (void) functionOffset;
Brian Paul959f8022000-03-19 01:10:11 +0000697 return NULL;
Brian Paul54f3aab2002-10-02 01:51:44 +0000698#endif /* USE_*_ASM */
Brian Paul959f8022000-03-19 01:10:11 +0000699}
700
701
Brian Paul767e15a2004-11-27 03:51:11 +0000702/**
Brian Paul54f3aab2002-10-02 01:51:44 +0000703 * This function inserts a new dispatch offset into the assembly language
704 * stub that was generated with the preceeding function.
705 */
706static void
Brian Paul767e15a2004-11-27 03:51:11 +0000707fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset)
Brian Paul54f3aab2002-10-02 01:51:44 +0000708{
709#if defined(USE_X86_ASM)
710
711 unsigned char *code = (unsigned char *) entrypoint;
712 *(unsigned int *)(code + 0x0b) = offset * 4;
713 *(unsigned int *)(code + 0x16) = offset * 4;
714
715#elif defined(USE_SPARC_ASM)
716
717 /* XXX this hasn't been tested! */
718 unsigned int *code = (unsigned int *) entrypoint;
Brian Paulc247c7f2004-11-22 19:27:40 +0000719#if (defined(__sparc_v9__) && (!defined(__linux__) || defined(__linux_sparc_64__)))
Brian Paul54f3aab2002-10-02 01:51:44 +0000720 code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
721 code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
722 code[6] |= ((offset * 8) >> 10);
723 code[7] |= ((offset * 8) & ((1 << 10) - 1));
724 __glapi_sparc_icache_flush(&code[6]);
Brian Paul9a90cd42003-12-01 22:40:26 +0000725#else /* __sparc_v9__ && !linux */
Brian Paul54f3aab2002-10-02 01:51:44 +0000726 code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
Brian Paul944ea202002-10-17 16:29:17 +0000727 code[2] |= (offset * 4);
Brian Paul54f3aab2002-10-02 01:51:44 +0000728 __glapi_sparc_icache_flush(&code[2]);
Brian Paul9a90cd42003-12-01 22:40:26 +0000729#endif /* __sparc_v9__ && !linux */
Brian Paul54f3aab2002-10-02 01:51:44 +0000730
Brian Paula6c423d2004-08-25 15:59:48 +0000731#else
732
733 /* an unimplemented architecture */
734 (void) entrypoint;
735 (void) offset;
736
Brian Paul54f3aab2002-10-02 01:51:44 +0000737#endif /* USE_*_ASM */
738}
739
Brian Paul959f8022000-03-19 01:10:11 +0000740
Brian Paul767e15a2004-11-27 03:51:11 +0000741/**
Brian Paul959f8022000-03-19 01:10:11 +0000742 * Add a new extension function entrypoint.
743 * Return: GL_TRUE = success or GL_FALSE = failure
744 */
745GLboolean
746_glapi_add_entrypoint(const char *funcName, GLuint offset)
747{
Brian Paul8ad10762002-10-11 17:41:03 +0000748 /* trivial rejection test */
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000749#ifdef MANGLE
750 if (!funcName || funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
Brian Paula6c423d2004-08-25 15:59:48 +0000751 return GL_FALSE;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000752#else
Brian Paul8ad10762002-10-11 17:41:03 +0000753 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
754 return GL_FALSE;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000755#endif
Brian Paul8ad10762002-10-11 17:41:03 +0000756
Brian Paul959f8022000-03-19 01:10:11 +0000757 /* first check if the named function is already statically present */
758 {
759 GLint index = get_static_proc_offset(funcName);
760 if (index >= 0) {
Brian Paulb51b0a82001-03-07 05:06:11 +0000761 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
Brian Paul959f8022000-03-19 01:10:11 +0000762 }
763 }
764
Brian Paul54f3aab2002-10-02 01:51:44 +0000765 /* See if this function has already been dynamically added */
Brian Paul959f8022000-03-19 01:10:11 +0000766 {
Brian Paul959f8022000-03-19 01:10:11 +0000767 GLuint i;
768 for (i = 0; i < NumExtEntryPoints; i++) {
769 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000770 /* function already registered */
Brian Paul959f8022000-03-19 01:10:11 +0000771 if (ExtEntryTable[i].Offset == offset) {
772 return GL_TRUE; /* offsets match */
773 }
Brian Paule4fcea22003-09-19 15:38:15 +0000774 else if (ExtEntryTable[i].Offset == (GLuint) ~0
Brian Paul54f3aab2002-10-02 01:51:44 +0000775 && offset < DISPATCH_TABLE_SIZE) {
776 /* need to patch-up the dispatch code */
Brian Paule4fcea22003-09-19 15:38:15 +0000777 if (offset != (GLuint) ~0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000778 fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
779 ExtEntryTable[i].Offset = offset;
780 }
781 return GL_TRUE;
782 }
Brian Paul959f8022000-03-19 01:10:11 +0000783 else {
784 return GL_FALSE; /* bad offset! */
785 }
786 }
787 }
Brian Paul959f8022000-03-19 01:10:11 +0000788 }
789
Brian Paul8ad10762002-10-11 17:41:03 +0000790 /* This is a new function, try to add it. */
791 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
792 offset >= DISPATCH_TABLE_SIZE) {
793 /* No space left */
794 return GL_FALSE;
795 }
796 else {
Brian Paul767e15a2004-11-27 03:51:11 +0000797 _glapi_proc entrypoint = generate_entrypoint(offset);
Brian Paul8ad10762002-10-11 17:41:03 +0000798 if (!entrypoint)
799 return GL_FALSE; /* couldn't generate assembly */
800
801 /* OK! */
802 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
803 ExtEntryTable[NumExtEntryPoints].Offset = offset;
804 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
805 NumExtEntryPoints++;
806
807 return GL_TRUE; /* success */
808 }
809
810 /* should never get here, silence compiler warnings */
Brian Paul959f8022000-03-19 01:10:11 +0000811 return GL_FALSE;
812}
813
814
Brian Paul767e15a2004-11-27 03:51:11 +0000815/**
Brian Paul959f8022000-03-19 01:10:11 +0000816 * Return offset of entrypoint for named function within dispatch table.
817 */
818GLint
819_glapi_get_proc_offset(const char *funcName)
820{
821 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000822 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000823 for (i = 0; i < NumExtEntryPoints; i++) {
824 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
825 return ExtEntryTable[i].Offset;
826 }
827 }
828
829 /* search static functions */
830 return get_static_proc_offset(funcName);
831}
832
833
834
Brian Paul767e15a2004-11-27 03:51:11 +0000835/**
836 * Return pointer to the named function. If the function name isn't found
837 * in the name of static functions, try generating a new API entrypoint on
838 * the fly with assembly language.
Brian Paul959f8022000-03-19 01:10:11 +0000839 */
Brian Paul767e15a2004-11-27 03:51:11 +0000840const _glapi_proc
Brian Paul959f8022000-03-19 01:10:11 +0000841_glapi_get_proc_address(const char *funcName)
842{
Brian Paulb51b0a82001-03-07 05:06:11 +0000843 GLuint i;
Brian Paula6ed6f42003-08-27 14:48:16 +0000844
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000845#ifdef MANGLE
846 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
847 return NULL;
848#else
Brian Paula6ed6f42003-08-27 14:48:16 +0000849 if (funcName[0] != 'g' || funcName[1] != 'l')
850 return NULL;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000851#endif
Brian Paula6ed6f42003-08-27 14:48:16 +0000852
853 /* search extension functions first */
Brian Paul959f8022000-03-19 01:10:11 +0000854 for (i = 0; i < NumExtEntryPoints; i++) {
855 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
856 return ExtEntryTable[i].Address;
857 }
858 }
859
860 /* search static functions */
Brian Paul54f3aab2002-10-02 01:51:44 +0000861 {
Brian Paul767e15a2004-11-27 03:51:11 +0000862 const _glapi_proc func = get_static_proc_address(funcName);
Brian Paul54f3aab2002-10-02 01:51:44 +0000863 if (func)
864 return func;
865 }
Brian Paul959f8022000-03-19 01:10:11 +0000866
Brian Paul54f3aab2002-10-02 01:51:44 +0000867 /* generate new entrypoint - use a temporary dispatch offset of
868 * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
869 * we'll put in the proper offset. If that never happens, and the
870 * user calls this function, he'll segfault. That's what you get
871 * when you try calling a GL function that doesn't really exist.
872 */
873 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
Brian Paul767e15a2004-11-27 03:51:11 +0000874 _glapi_proc entrypoint = generate_entrypoint(~0);
Brian Paul54f3aab2002-10-02 01:51:44 +0000875 if (!entrypoint)
876 return GL_FALSE;
877
878 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
879 ExtEntryTable[NumExtEntryPoints].Offset = ~0;
880 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
881 NumExtEntryPoints++;
882
883 return entrypoint;
884 }
885 else {
886 /* no space for new functions! */
887 return NULL;
888 }
889}
Brian Paul959f8022000-03-19 01:10:11 +0000890
891
892
Brian Paul767e15a2004-11-27 03:51:11 +0000893/**
Brian Paul959f8022000-03-19 01:10:11 +0000894 * Return the name of the function at the given dispatch offset.
895 * This is only intended for debugging.
896 */
897const char *
898_glapi_get_proc_name(GLuint offset)
899{
Brian Paul959f8022000-03-19 01:10:11 +0000900 GLuint i;
Ian Romanick78677992004-05-27 00:05:13 +0000901 const char * n;
Brian Paul54f3aab2002-10-02 01:51:44 +0000902
903 /* search built-in functions */
Ian Romanick78677992004-05-27 00:05:13 +0000904 n = get_static_proc_name(offset);
905 if ( n != NULL ) {
906 return n;
Brian Paul959f8022000-03-19 01:10:11 +0000907 }
908
909 /* search added extension functions */
910 for (i = 0; i < NumExtEntryPoints; i++) {
911 if (ExtEntryTable[i].Offset == offset) {
912 return ExtEntryTable[i].Name;
913 }
914 }
915 return NULL;
916}
917
918
919
Brian Paul767e15a2004-11-27 03:51:11 +0000920/**
Brian Paul54f3aab2002-10-02 01:51:44 +0000921 * Return size of dispatch table struct as number of functions (or
922 * slots).
923 */
924GLuint
925_glapi_get_dispatch_table_size(void)
926{
927 return DISPATCH_TABLE_SIZE;
928}
929
930
931
Brian Paul767e15a2004-11-27 03:51:11 +0000932/**
Brian Paul54f3aab2002-10-02 01:51:44 +0000933 * Get API dispatcher version string.
934 */
935const char *
936_glapi_get_version(void)
937{
938 return "20021001"; /* YYYYMMDD */
939}
940
941
942
Brian Paul767e15a2004-11-27 03:51:11 +0000943/**
Brian Paul959f8022000-03-19 01:10:11 +0000944 * Make sure there are no NULL pointers in the given dispatch table.
Brian Paul5104b4d2002-03-07 21:50:41 +0000945 * Intended for debugging purposes.
Brian Paul959f8022000-03-19 01:10:11 +0000946 */
947void
948_glapi_check_table(const struct _glapi_table *table)
949{
Brian Paul5104b4d2002-03-07 21:50:41 +0000950#ifdef DEBUG
Brian Paul959f8022000-03-19 01:10:11 +0000951 const GLuint entries = _glapi_get_dispatch_table_size();
952 const void **tab = (const void **) table;
953 GLuint i;
954 for (i = 1; i < entries; i++) {
955 assert(tab[i]);
956 }
957
Brian Paul959f8022000-03-19 01:10:11 +0000958 /* Do some spot checks to be sure that the dispatch table
959 * slots are assigned correctly.
960 */
961 {
962 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
963 char *BeginFunc = (char*) &table->Begin;
964 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
965 assert(BeginOffset == _gloffset_Begin);
966 assert(BeginOffset == offset);
967 }
968 {
969 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
970 char *viewportFunc = (char*) &table->Viewport;
971 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
972 assert(viewportOffset == _gloffset_Viewport);
973 assert(viewportOffset == offset);
974 }
975 {
976 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
977 char *VertexPointerFunc = (char*) &table->VertexPointer;
978 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
979 assert(VertexPointerOffset == _gloffset_VertexPointer);
980 assert(VertexPointerOffset == offset);
981 }
982 {
983 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
984 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
985 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
986 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
987 assert(ResetMinMaxOffset == offset);
988 }
989 {
990 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
991 char *blendColorFunc = (char*) &table->BlendColor;
992 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
993 assert(blendColorOffset == _gloffset_BlendColor);
994 assert(blendColorOffset == offset);
995 }
996 {
997 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
998 char *istextureFunc = (char*) &table->IsTextureEXT;
999 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
1000 assert(istextureOffset == _gloffset_IsTextureEXT);
1001 assert(istextureOffset == offset);
1002 }
Brian Paula14cbff2000-10-27 18:31:21 +00001003 {
1004 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
1005 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
1006 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
1007 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
1008 assert(secondaryColor3fOffset == offset);
Brian Paul767e15a2004-11-27 03:51:11 +00001009 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (_glapi_proc) &glSecondaryColor3fEXT);
Brian Paula14cbff2000-10-27 18:31:21 +00001010 }
Brian Paul91d6f122002-05-29 15:23:16 +00001011 {
1012 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
1013 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
1014 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
1015 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
1016 assert(pointParameterivOffset == offset);
Brian Paul767e15a2004-11-27 03:51:11 +00001017 assert(_glapi_get_proc_address("glPointParameterivNV") == &glPointParameterivNV);
Brian Paul91d6f122002-05-29 15:23:16 +00001018 }
Brian Paul54f3aab2002-10-02 01:51:44 +00001019 {
1020 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
1021 char *setFenceFunc = (char*) &table->SetFenceNV;
1022 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
1023 assert(setFenceOffset == _gloffset_SetFenceNV);
1024 assert(setFenceOffset == offset);
Brian Paul767e15a2004-11-27 03:51:11 +00001025 assert(_glapi_get_proc_address("glSetFenceNV") == &glSetFenceNV);
Brian Paul54f3aab2002-10-02 01:51:44 +00001026 }
Brian Paula6c423d2004-08-25 15:59:48 +00001027#else
1028 (void) table;
Brian Paul959f8022000-03-19 01:10:11 +00001029#endif
1030}