blob: d28e7c4a9396bc5debdf4336e255ab80db63690d [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 *****/
136/* if we support thread-safety, build a special dispatch table for use
137 * in thread-safety mode (ThreadSafe == GL_TRUE). Each entry in the
138 * dispatch table will call _glthread_GetTSD() to get the actual dispatch
139 * table bound to the current thread, then jump through that table.
140 */
141
142#if defined(THREADS)
143
144static GLboolean ThreadSafe = GL_FALSE; /* In thread-safe mode? */
145static _glthread_TSD DispatchTSD; /* Per-thread dispatch pointer */
146static _glthread_TSD RealDispatchTSD; /* only when using override */
147static _glthread_TSD ContextTSD; /* Per-thread context pointer */
148
149
150#define KEYWORD1 static
151#define KEYWORD2 GLAPIENTRY
152#define NAME(func) _ts_##func
153
154#define DISPATCH(FUNC, ARGS, MESSAGE) \
155 struct _glapi_table *dispatch; \
156 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
157 if (!dispatch) \
158 dispatch = (struct _glapi_table *) __glapi_noop_table; \
159 (dispatch->FUNC) ARGS
160
161#define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \
162 struct _glapi_table *dispatch; \
163 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
164 if (!dispatch) \
165 dispatch = (struct _glapi_table *) __glapi_noop_table; \
166 return (dispatch->FUNC) ARGS
167
168#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
169#define UNUSED_TABLE_NAME __usused_threadsafe_functions
170
171#define TABLE_ENTRY(name) (void *) _ts_##name
172
173static int _ts_Unused(void)
174{
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;
Brian Paulab0c8862001-01-23 23:35:47 +0000187struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul0f710251999-12-15 15:02:30 +0000188
Brian Paul8f91fb61999-12-17 14:51:28 +0000189/* Used when thread safety disabled */
Brian Paulf9b97d92000-01-28 20:17:42 +0000190void *_glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000191
Brian Paul0f710251999-12-15 15:02:30 +0000192
Brian Paulab0c8862001-01-23 23:35:47 +0000193static GLboolean DispatchOverride = GL_FALSE;
194
195
Brian Paul54f3aab2002-10-02 01:51:44 +0000196
Brian Paul3c257e12001-03-28 17:19:58 +0000197/* strdup() is actually not a standard ANSI C or POSIX routine.
198 * Irix will not define it if ANSI mode is in effect.
199 */
200static char *
201str_dup(const char *str)
Randy Frankd7361e12000-03-27 21:13:58 +0000202{
Brian Paulfffb8092000-03-29 18:46:11 +0000203 char *copy;
204 copy = (char*) malloc(strlen(str) + 1);
205 if (!copy)
206 return NULL;
207 strcpy(copy, str);
208 return copy;
Randy Frankd7361e12000-03-27 21:13:58 +0000209}
210
Brian Paul7fb54ae1999-11-19 22:33:50 +0000211
Brian Paulbb72d321999-12-16 17:31:59 +0000212
213/*
214 * We should call this periodically from a function such as glXMakeCurrent
Brian Paul5104b4d2002-03-07 21:50:41 +0000215 * in order to test if multiple threads are being used.
Brian Paulbb72d321999-12-16 17:31:59 +0000216 */
217void
218_glapi_check_multithread(void)
219{
220#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000221 if (!ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000222 static unsigned long knownID;
223 static GLboolean firstCall = GL_TRUE;
224 if (firstCall) {
225 knownID = _glthread_GetID();
226 firstCall = GL_FALSE;
227 }
228 else if (knownID != _glthread_GetID()) {
Brian Paul26e14d22000-01-05 04:36:17 +0000229 ThreadSafe = GL_TRUE;
Brian Paulbb72d321999-12-16 17:31:59 +0000230 }
231 }
Brian Paul26e14d22000-01-05 04:36:17 +0000232 if (ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000233 /* make sure that this thread's dispatch pointer isn't null */
234 if (!_glapi_get_dispatch()) {
235 _glapi_set_dispatch(NULL);
236 }
237 }
238#endif
239}
240
241
242
243/*
Brian Paul8f91fb61999-12-17 14:51:28 +0000244 * Set the current context pointer for this thread.
245 * The context pointer is an opaque type which should be cast to
246 * void from the real context pointer type.
247 */
248void
Brian Paulf9b97d92000-01-28 20:17:42 +0000249_glapi_set_context(void *context)
Brian Paul8f91fb61999-12-17 14:51:28 +0000250{
251#if defined(THREADS)
Brian Paul3c27be32000-02-10 21:27:48 +0000252 _glthread_SetTSD(&ContextTSD, context);
Brian Paul26e14d22000-01-05 04:36:17 +0000253 if (ThreadSafe)
Brian Paulf9b97d92000-01-28 20:17:42 +0000254 _glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000255 else
Brian Paulf9b97d92000-01-28 20:17:42 +0000256 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000257#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000258 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000259#endif
260}
261
262
263
264/*
265 * Get the current context pointer for this thread.
266 * The context pointer is an opaque type which should be cast from
267 * void to the real context pointer type.
268 */
269void *
Brian Paulf9b97d92000-01-28 20:17:42 +0000270_glapi_get_context(void)
Brian Paul8f91fb61999-12-17 14:51:28 +0000271{
272#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000273 if (ThreadSafe) {
Brian Paul8f91fb61999-12-17 14:51:28 +0000274 return _glthread_GetTSD(&ContextTSD);
275 }
276 else {
Brian Paulf9b97d92000-01-28 20:17:42 +0000277 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000278 }
279#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000280 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000281#endif
282}
283
284
285
286/*
Brian Paul7fb54ae1999-11-19 22:33:50 +0000287 * Set the global or per-thread dispatch table pointer.
288 */
289void
290_glapi_set_dispatch(struct _glapi_table *dispatch)
291{
292 if (!dispatch) {
293 /* use the no-op functions */
Brian Paul8ceb5c32000-02-24 22:14:04 +0000294 dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000295 }
296#ifdef DEBUG
297 else {
298 _glapi_check_table(dispatch);
299 }
300#endif
301
302#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000303 if (DispatchOverride) {
304 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000305 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000306 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000307 else
Brian Paulab0c8862001-01-23 23:35:47 +0000308 _glapi_RealDispatch = dispatch;
Brian Paul3b18a362000-09-26 15:27:20 +0000309 }
310 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000311 /* normal operation */
Brian Paul3b18a362000-09-26 15:27:20 +0000312 _glthread_SetTSD(&DispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000313 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000314 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000315 else
316 _glapi_Dispatch = dispatch;
317 }
Brian Paul3a71d052000-09-05 20:17:37 +0000318#else /*THREADS*/
Brian Paulab0c8862001-01-23 23:35:47 +0000319 if (DispatchOverride) {
320 _glapi_RealDispatch = dispatch;
321 }
322 else {
323 _glapi_Dispatch = dispatch;
324 }
Brian Paul3a71d052000-09-05 20:17:37 +0000325#endif /*THREADS*/
Brian Paul7fb54ae1999-11-19 22:33:50 +0000326}
327
328
Brian Paulbb72d321999-12-16 17:31:59 +0000329
Brian Paul7fb54ae1999-11-19 22:33:50 +0000330/*
Brian Paulbb72d321999-12-16 17:31:59 +0000331 * Return pointer to current dispatch table for calling thread.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000332 */
333struct _glapi_table *
334_glapi_get_dispatch(void)
335{
336#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000337 if (ThreadSafe) {
Brian Paulab0c8862001-01-23 23:35:47 +0000338 if (DispatchOverride) {
339 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
340 }
341 else {
342 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
343 }
Brian Paulbb72d321999-12-16 17:31:59 +0000344 }
Brian Paul590d3471999-12-17 12:20:23 +0000345 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000346 if (DispatchOverride) {
347 assert(_glapi_RealDispatch);
348 return _glapi_RealDispatch;
349 }
350 else {
351 assert(_glapi_Dispatch);
352 return _glapi_Dispatch;
353 }
Brian Paul590d3471999-12-17 12:20:23 +0000354 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000355#else
Brian Paulc2319b42000-01-17 19:28:31 +0000356 return _glapi_Dispatch;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000357#endif
358}
359
360
Brian Paulab0c8862001-01-23 23:35:47 +0000361/*
362 * Notes on dispatch overrride:
363 *
364 * Dispatch override allows an external agent to hook into the GL dispatch
365 * mechanism before execution goes into the core rendering library. For
366 * example, a trace mechanism would insert itself as an overrider, print
367 * logging info for each GL function, then dispatch to the real GL function.
368 *
369 * libGLS (GL Stream library) is another agent that might use override.
370 *
371 * We don't allow more than one layer of overriding at this time.
372 * In the future we may allow nested/layered override. In that case
373 * _glapi_begin_dispatch_override() will return an override layer,
374 * _glapi_end_dispatch_override(layer) will remove an override layer
375 * and _glapi_get_override_dispatch(layer) will return the dispatch
376 * table for a given override layer. layer = 0 will be the "real"
377 * dispatch table.
378 */
379
380/*
381 * Return: dispatch override layer number.
382 */
383int
384_glapi_begin_dispatch_override(struct _glapi_table *override)
Brian Paul3a71d052000-09-05 20:17:37 +0000385{
Brian Paulab0c8862001-01-23 23:35:47 +0000386 struct _glapi_table *real = _glapi_get_dispatch();
387
388 assert(!DispatchOverride); /* can't nest at this time */
389 DispatchOverride = GL_TRUE;
390
391 _glapi_set_dispatch(real);
Brian Paul3a71d052000-09-05 20:17:37 +0000392
393#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000394 _glthread_SetTSD(&DispatchTSD, (void *) override);
395 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000396 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000397 else
398 _glapi_Dispatch = override;
399#else
400 _glapi_Dispatch = override;
401#endif
402 return 1;
403}
404
405
406void
407_glapi_end_dispatch_override(int layer)
408{
409 struct _glapi_table *real = _glapi_get_dispatch();
410 (void) layer;
411 DispatchOverride = GL_FALSE;
412 _glapi_set_dispatch(real);
413 /* the rest of this isn't needed, just play it safe */
414#if defined(THREADS)
415 _glthread_SetTSD(&RealDispatchTSD, NULL);
416#endif
417 _glapi_RealDispatch = NULL;
418}
419
420
421struct _glapi_table *
422_glapi_get_override_dispatch(int layer)
423{
424 if (layer == 0) {
425 return _glapi_get_dispatch();
Brian Paul3a71d052000-09-05 20:17:37 +0000426 }
427 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000428 if (DispatchOverride) {
429#if defined(THREADS)
430 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
Brian Paul3a71d052000-09-05 20:17:37 +0000431#else
Brian Paulab0c8862001-01-23 23:35:47 +0000432 return _glapi_Dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000433#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000434 }
435 else {
436 return NULL;
437 }
438 }
Brian Paul3a71d052000-09-05 20:17:37 +0000439}
Brian Paulab0c8862001-01-23 23:35:47 +0000440
Brian Paul3a71d052000-09-05 20:17:37 +0000441
Brian Paul959f8022000-03-19 01:10:11 +0000442struct name_address_offset {
443 const char *Name;
444 GLvoid *Address;
445 GLuint Offset;
446};
447
Brian Paul0c239fc1999-12-16 12:38:11 +0000448
Ian Romanick78677992004-05-27 00:05:13 +0000449#define NEED_FUNCTION_POINTER
450
Brian Paul54f3aab2002-10-02 01:51:44 +0000451/* The code in this file is auto-generated with Python */
Brian Paulb5fd8862001-11-18 22:48:11 +0000452#include "glprocs.h"
Brian Paul7fb54ae1999-11-19 22:33:50 +0000453
Brian Paul959f8022000-03-19 01:10:11 +0000454
Ian Romanick78677992004-05-27 00:05:13 +0000455static const glprocs_table_t *
456find_entry( const char * n )
457{
458 unsigned i;
459
460 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
461 const char * test_name;
462
463 test_name = gl_string_table + static_functions[i].Name_offset;
464 if (strcmp(test_name, n) == 0) {
465 return & static_functions[i];
466 }
467 }
468 return NULL;
469}
470
Brian Paul959f8022000-03-19 01:10:11 +0000471
472/*
473 * Return dispatch table offset of the named static (built-in) function.
474 * Return -1 if function not found.
475 */
476static GLint
477get_static_proc_offset(const char *funcName)
478{
Ian Romanick78677992004-05-27 00:05:13 +0000479 const glprocs_table_t * const f = find_entry( funcName );
480
481 if ( f != NULL ) {
482 return f->Offset;
Brian Paul959f8022000-03-19 01:10:11 +0000483 }
484 return -1;
485}
486
487
488/*
489 * Return dispatch function address the named static (built-in) function.
490 * Return NULL if function not found.
491 */
Ian Romanick78677992004-05-27 00:05:13 +0000492static const GLvoid *
Brian Paul959f8022000-03-19 01:10:11 +0000493get_static_proc_address(const char *funcName)
494{
Ian Romanick78677992004-05-27 00:05:13 +0000495 const glprocs_table_t * const f = find_entry( funcName );
496 return ( f != NULL ) ? f->Address : NULL;
497}
498
499
500static const char *
501get_static_proc_name( GLuint offset )
502{
503 unsigned i;
504
505 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
506 if (static_functions[i].Offset == offset) {
507 return gl_string_table + static_functions[i].Name_offset;
Brian Paul9c7ca852000-10-19 20:13:12 +0000508 }
509 }
510 return NULL;
Brian Paul959f8022000-03-19 01:10:11 +0000511}
512
513
514
515/**********************************************************************
516 * Extension function management.
517 */
518
Brian Paul54f3aab2002-10-02 01:51:44 +0000519/*
520 * Number of extension functions which we can dynamically add at runtime.
521 */
522#define MAX_EXTENSION_FUNCS 300
Brian Paul959f8022000-03-19 01:10:11 +0000523
Brian Paul54f3aab2002-10-02 01:51:44 +0000524
525/*
526 * The disptach table size (number of entries) is the sizeof the
527 * _glapi_table struct plus the number of dynamic entries we can add.
528 * The extra slots can be filled in by DRI drivers that register new extension
529 * functions.
530 */
531#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
532
Brian Paul959f8022000-03-19 01:10:11 +0000533
534static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
535static GLuint NumExtEntryPoints = 0;
536
davem694a497e62001-06-06 22:55:28 +0000537#ifdef USE_SPARC_ASM
538extern void __glapi_sparc_icache_flush(unsigned int *);
539#endif
Brian Paul959f8022000-03-19 01:10:11 +0000540
541/*
542 * Generate a dispatch function (entrypoint) which jumps through
543 * the given slot number (offset) in the current dispatch table.
544 * We need assembly language in order to accomplish this.
545 */
546static void *
547generate_entrypoint(GLuint functionOffset)
548{
549#if defined(USE_X86_ASM)
550 /*
551 * This x86 code contributed by Josh Vanderhoof.
552 *
553 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
554 * 00 01 02 03 04
555 * 5: 85 c0 testl %eax,%eax
556 * 05 06
557 * 7: 74 06 je f <entrypoint+0xf>
558 * 07 08
559 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
560 * 09 0a 0b 0c 0d 0e
561 * f: e8 fc ff ff ff call __glapi_get_dispatch
562 * 0f 10 11 12 13
563 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
564 * 14 15 16 17 18 19
565 */
Brian Paul54f3aab2002-10-02 01:51:44 +0000566 static const unsigned char insn_template[] = {
Brian Paul959f8022000-03-19 01:10:11 +0000567 0xa1, 0x00, 0x00, 0x00, 0x00,
568 0x85, 0xc0,
569 0x74, 0x06,
570 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
571 0xe8, 0x00, 0x00, 0x00, 0x00,
572 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
573 };
Brian Pauldec2a4d2002-10-29 15:03:14 +0000574 unsigned char *code = (unsigned char *) malloc(sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000575 unsigned int next_insn;
576 if (code) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000577 memcpy(code, insn_template, sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000578
579 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
580 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
581 next_insn = (unsigned int)(code + 0x14);
582 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
583 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
584 }
585 return code;
davem69775355a2001-06-05 23:54:00 +0000586#elif defined(USE_SPARC_ASM)
587
Brian Paul9a90cd42003-12-01 22:40:26 +0000588#if defined(__sparc_v9__) && !defined(__linux__)
davem69775355a2001-06-05 23:54:00 +0000589 static const unsigned int insn_template[] = {
590 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
591 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
592 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
593 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
594 0x8528b020, /* sllx %g2, 32, %g2 */
595 0xc2584002, /* ldx [%g1 + %g2], %g1 */
596 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
597 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
598 0xc6584002, /* ldx [%g1 + %g2], %g3 */
599 0x81c0c000, /* jmpl %g3, %g0 */
600 0x01000000 /* nop */
601 };
602#else
603 static const unsigned int insn_template[] = {
604 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
605 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
606 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
607 0x81c0c000, /* jmpl %g3, %g0 */
608 0x01000000 /* nop */
609 };
610#endif
Brian Pauldec2a4d2002-10-29 15:03:14 +0000611 unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
davem69775355a2001-06-05 23:54:00 +0000612 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
613 if (code) {
614 memcpy(code, insn_template, sizeof(insn_template));
615
Brian Paul9a90cd42003-12-01 22:40:26 +0000616#if defined(__sparc_v9__) && !defined(__linux__)
davem69775355a2001-06-05 23:54:00 +0000617 code[0] |= (glapi_addr >> (32 + 10));
618 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
davem694a497e62001-06-06 22:55:28 +0000619 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000620 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
621 code[3] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000622 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000623 code[6] |= ((functionOffset * 8) >> 10);
624 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000625 __glapi_sparc_icache_flush(&code[6]);
davem69775355a2001-06-05 23:54:00 +0000626#else
627 code[0] |= (glapi_addr >> 10);
628 code[1] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000629 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000630 code[2] |= (functionOffset * 4);
davem694a497e62001-06-06 22:55:28 +0000631 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000632#endif
633 }
634 return code;
Brian Paul959f8022000-03-19 01:10:11 +0000635#else
636 return NULL;
Brian Paul54f3aab2002-10-02 01:51:44 +0000637#endif /* USE_*_ASM */
Brian Paul959f8022000-03-19 01:10:11 +0000638}
639
640
Brian Paul54f3aab2002-10-02 01:51:44 +0000641/*
642 * This function inserts a new dispatch offset into the assembly language
643 * stub that was generated with the preceeding function.
644 */
645static void
646fill_in_entrypoint_offset(void *entrypoint, GLuint offset)
647{
648#if defined(USE_X86_ASM)
649
650 unsigned char *code = (unsigned char *) entrypoint;
651 *(unsigned int *)(code + 0x0b) = offset * 4;
652 *(unsigned int *)(code + 0x16) = offset * 4;
653
654#elif defined(USE_SPARC_ASM)
655
656 /* XXX this hasn't been tested! */
657 unsigned int *code = (unsigned int *) entrypoint;
Brian Paul9a90cd42003-12-01 22:40:26 +0000658#if defined(__sparc_v9__) && !defined(__linux__)
Brian Paul54f3aab2002-10-02 01:51:44 +0000659 code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
660 code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
661 code[6] |= ((offset * 8) >> 10);
662 code[7] |= ((offset * 8) & ((1 << 10) - 1));
663 __glapi_sparc_icache_flush(&code[6]);
Brian Paul9a90cd42003-12-01 22:40:26 +0000664#else /* __sparc_v9__ && !linux */
Brian Paul54f3aab2002-10-02 01:51:44 +0000665 code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
Brian Paul944ea202002-10-17 16:29:17 +0000666 code[2] |= (offset * 4);
Brian Paul54f3aab2002-10-02 01:51:44 +0000667 __glapi_sparc_icache_flush(&code[2]);
Brian Paul9a90cd42003-12-01 22:40:26 +0000668#endif /* __sparc_v9__ && !linux */
Brian Paul54f3aab2002-10-02 01:51:44 +0000669
670#endif /* USE_*_ASM */
671}
672
Brian Paul959f8022000-03-19 01:10:11 +0000673
674/*
675 * Add a new extension function entrypoint.
676 * Return: GL_TRUE = success or GL_FALSE = failure
677 */
678GLboolean
679_glapi_add_entrypoint(const char *funcName, GLuint offset)
680{
Brian Paul8ad10762002-10-11 17:41:03 +0000681 /* trivial rejection test */
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000682#ifdef MANGLE
683 if (!funcName || funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
684 return NULL;
685#else
Brian Paul8ad10762002-10-11 17:41:03 +0000686 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
687 return GL_FALSE;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000688#endif
Brian Paul8ad10762002-10-11 17:41:03 +0000689
Brian Paul959f8022000-03-19 01:10:11 +0000690 /* first check if the named function is already statically present */
691 {
692 GLint index = get_static_proc_offset(funcName);
693 if (index >= 0) {
Brian Paulb51b0a82001-03-07 05:06:11 +0000694 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
Brian Paul959f8022000-03-19 01:10:11 +0000695 }
696 }
697
Brian Paul54f3aab2002-10-02 01:51:44 +0000698 /* See if this function has already been dynamically added */
Brian Paul959f8022000-03-19 01:10:11 +0000699 {
Brian Paul959f8022000-03-19 01:10:11 +0000700 GLuint i;
701 for (i = 0; i < NumExtEntryPoints; i++) {
702 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000703 /* function already registered */
Brian Paul959f8022000-03-19 01:10:11 +0000704 if (ExtEntryTable[i].Offset == offset) {
705 return GL_TRUE; /* offsets match */
706 }
Brian Paule4fcea22003-09-19 15:38:15 +0000707 else if (ExtEntryTable[i].Offset == (GLuint) ~0
Brian Paul54f3aab2002-10-02 01:51:44 +0000708 && offset < DISPATCH_TABLE_SIZE) {
709 /* need to patch-up the dispatch code */
Brian Paule4fcea22003-09-19 15:38:15 +0000710 if (offset != (GLuint) ~0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000711 fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
712 ExtEntryTable[i].Offset = offset;
713 }
714 return GL_TRUE;
715 }
Brian Paul959f8022000-03-19 01:10:11 +0000716 else {
717 return GL_FALSE; /* bad offset! */
718 }
719 }
720 }
Brian Paul959f8022000-03-19 01:10:11 +0000721 }
722
Brian Paul8ad10762002-10-11 17:41:03 +0000723 /* This is a new function, try to add it. */
724 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
725 offset >= DISPATCH_TABLE_SIZE) {
726 /* No space left */
727 return GL_FALSE;
728 }
729 else {
730 void *entrypoint = generate_entrypoint(offset);
731 if (!entrypoint)
732 return GL_FALSE; /* couldn't generate assembly */
733
734 /* OK! */
735 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
736 ExtEntryTable[NumExtEntryPoints].Offset = offset;
737 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
738 NumExtEntryPoints++;
739
740 return GL_TRUE; /* success */
741 }
742
743 /* should never get here, silence compiler warnings */
Brian Paul959f8022000-03-19 01:10:11 +0000744 return GL_FALSE;
745}
746
747
Brian Paul959f8022000-03-19 01:10:11 +0000748/*
749 * Return offset of entrypoint for named function within dispatch table.
750 */
751GLint
752_glapi_get_proc_offset(const char *funcName)
753{
754 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000755 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000756 for (i = 0; i < NumExtEntryPoints; i++) {
757 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
758 return ExtEntryTable[i].Offset;
759 }
760 }
761
762 /* search static functions */
763 return get_static_proc_offset(funcName);
764}
765
766
767
768/*
769 * Return entrypoint for named function.
770 */
771const GLvoid *
772_glapi_get_proc_address(const char *funcName)
773{
Brian Paulb51b0a82001-03-07 05:06:11 +0000774 GLuint i;
Brian Paula6ed6f42003-08-27 14:48:16 +0000775
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000776#ifdef MANGLE
777 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
778 return NULL;
779#else
Brian Paula6ed6f42003-08-27 14:48:16 +0000780 if (funcName[0] != 'g' || funcName[1] != 'l')
781 return NULL;
Brian Paulf7b4e0d2004-04-23 20:33:07 +0000782#endif
Brian Paula6ed6f42003-08-27 14:48:16 +0000783
784 /* search extension functions first */
Brian Paul959f8022000-03-19 01:10:11 +0000785 for (i = 0; i < NumExtEntryPoints; i++) {
786 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
787 return ExtEntryTable[i].Address;
788 }
789 }
790
791 /* search static functions */
Brian Paul54f3aab2002-10-02 01:51:44 +0000792 {
793 const GLvoid *func = get_static_proc_address(funcName);
794 if (func)
795 return func;
796 }
Brian Paul959f8022000-03-19 01:10:11 +0000797
Brian Paul54f3aab2002-10-02 01:51:44 +0000798 /* generate new entrypoint - use a temporary dispatch offset of
799 * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
800 * we'll put in the proper offset. If that never happens, and the
801 * user calls this function, he'll segfault. That's what you get
802 * when you try calling a GL function that doesn't really exist.
803 */
804 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
805 GLvoid *entrypoint = generate_entrypoint(~0);
806 if (!entrypoint)
807 return GL_FALSE;
808
809 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
810 ExtEntryTable[NumExtEntryPoints].Offset = ~0;
811 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
812 NumExtEntryPoints++;
813
814 return entrypoint;
815 }
816 else {
817 /* no space for new functions! */
818 return NULL;
819 }
820}
Brian Paul959f8022000-03-19 01:10:11 +0000821
822
823
824/*
825 * Return the name of the function at the given dispatch offset.
826 * This is only intended for debugging.
827 */
828const char *
829_glapi_get_proc_name(GLuint offset)
830{
Brian Paul959f8022000-03-19 01:10:11 +0000831 GLuint i;
Ian Romanick78677992004-05-27 00:05:13 +0000832 const char * n;
Brian Paul54f3aab2002-10-02 01:51:44 +0000833
834 /* search built-in functions */
Ian Romanick78677992004-05-27 00:05:13 +0000835 n = get_static_proc_name(offset);
836 if ( n != NULL ) {
837 return n;
Brian Paul959f8022000-03-19 01:10:11 +0000838 }
839
840 /* search added extension functions */
841 for (i = 0; i < NumExtEntryPoints; i++) {
842 if (ExtEntryTable[i].Offset == offset) {
843 return ExtEntryTable[i].Name;
844 }
845 }
846 return NULL;
847}
848
849
850
851/*
Brian Paul54f3aab2002-10-02 01:51:44 +0000852 * Return size of dispatch table struct as number of functions (or
853 * slots).
854 */
855GLuint
856_glapi_get_dispatch_table_size(void)
857{
858 return DISPATCH_TABLE_SIZE;
859}
860
861
862
863/*
864 * Get API dispatcher version string.
865 */
866const char *
867_glapi_get_version(void)
868{
869 return "20021001"; /* YYYYMMDD */
870}
871
872
873
874/*
Brian Paul959f8022000-03-19 01:10:11 +0000875 * Make sure there are no NULL pointers in the given dispatch table.
Brian Paul5104b4d2002-03-07 21:50:41 +0000876 * Intended for debugging purposes.
Brian Paul959f8022000-03-19 01:10:11 +0000877 */
878void
879_glapi_check_table(const struct _glapi_table *table)
880{
Brian Paul5104b4d2002-03-07 21:50:41 +0000881#ifdef DEBUG
Brian Paul959f8022000-03-19 01:10:11 +0000882 const GLuint entries = _glapi_get_dispatch_table_size();
883 const void **tab = (const void **) table;
884 GLuint i;
885 for (i = 1; i < entries; i++) {
886 assert(tab[i]);
887 }
888
Brian Paul959f8022000-03-19 01:10:11 +0000889 /* Do some spot checks to be sure that the dispatch table
890 * slots are assigned correctly.
891 */
892 {
893 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
894 char *BeginFunc = (char*) &table->Begin;
895 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
896 assert(BeginOffset == _gloffset_Begin);
897 assert(BeginOffset == offset);
898 }
899 {
900 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
901 char *viewportFunc = (char*) &table->Viewport;
902 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
903 assert(viewportOffset == _gloffset_Viewport);
904 assert(viewportOffset == offset);
905 }
906 {
907 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
908 char *VertexPointerFunc = (char*) &table->VertexPointer;
909 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
910 assert(VertexPointerOffset == _gloffset_VertexPointer);
911 assert(VertexPointerOffset == offset);
912 }
913 {
914 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
915 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
916 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
917 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
918 assert(ResetMinMaxOffset == offset);
919 }
920 {
921 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
922 char *blendColorFunc = (char*) &table->BlendColor;
923 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
924 assert(blendColorOffset == _gloffset_BlendColor);
925 assert(blendColorOffset == offset);
926 }
927 {
928 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
929 char *istextureFunc = (char*) &table->IsTextureEXT;
930 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
931 assert(istextureOffset == _gloffset_IsTextureEXT);
932 assert(istextureOffset == offset);
933 }
Brian Paula14cbff2000-10-27 18:31:21 +0000934 {
935 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
936 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
937 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
938 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
939 assert(secondaryColor3fOffset == offset);
940 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
941 }
Brian Paul91d6f122002-05-29 15:23:16 +0000942 {
943 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
944 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
945 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
946 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
947 assert(pointParameterivOffset == offset);
948 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
949 }
Brian Paul54f3aab2002-10-02 01:51:44 +0000950 {
951 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
952 char *setFenceFunc = (char*) &table->SetFenceNV;
953 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
954 assert(setFenceOffset == _gloffset_SetFenceNV);
955 assert(setFenceOffset == offset);
956 assert(_glapi_get_proc_address("glSetFenceNV") == (void *) &glSetFenceNV);
957 }
Brian Paul959f8022000-03-19 01:10:11 +0000958#endif
959}