blob: d50a37bd9ffbfbfc13ffed388ea6dc24ca028a20 [file] [log] [blame]
Brian Paul91d6f122002-05-29 15:23:16 +00001/* $Id: glapi.c,v 1.62 2002/05/29 15:23:16 brianp Exp $ */
Brian Paulfbd8f211999-11-11 01:22:25 +00002
3/*
4 * Mesa 3-D graphics library
Brian Paul5104b4d2002-03-07 21:50:41 +00005 * Version: 4.1
Brian Paulfbd8f211999-11-11 01:22:25 +00006 *
Brian Paul5104b4d2002-03-07 21:50:41 +00007 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
Brian Paulfbd8f211999-11-11 01:22:25 +00008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
Brian Paul7e1161b1999-11-25 18:17:04 +000028/*
29 * This file manages the OpenGL API dispatch layer.
30 * The dispatch table (struct _glapi_table) is basically just a list
31 * of function pointers.
32 * There are functions to set/get the current dispatch table for the
33 * current thread and to manage registration/dispatch of dynamically
34 * added extension functions.
Brian Paul9f943992000-01-28 19:03:33 +000035 *
36 * It's intended that this file and the other glapi*.[ch] files are
37 * flexible enough to be reused in several places: XFree86, DRI-
38 * based libGL.so, and perhaps the SGI SI.
39 *
40 * There are no dependencies on Mesa in this code.
Brian Paulab0c8862001-01-23 23:35:47 +000041 *
42 * Versions (API changes):
43 * 2000/02/23 - original version for Mesa 3.3 and XFree86 4.0
44 * 2001/01/16 - added dispatch override feature for Mesa 3.5
Brian Paul7e1161b1999-11-25 18:17:04 +000045 */
46
47
48
Brian Paul3c27be32000-02-10 21:27:48 +000049#include "glheader.h"
Brian Paulfbd8f211999-11-11 01:22:25 +000050#include "glapi.h"
Brian Paul0c239fc1999-12-16 12:38:11 +000051#include "glapioffsets.h"
52#include "glapitable.h"
Brian Paul9f943992000-01-28 19:03:33 +000053#include "glthread.h"
Brian Paulbb72d321999-12-16 17:31:59 +000054
Brian Paul3c257e12001-03-28 17:19:58 +000055/***** BEGIN NO-OP DISPATCH *****/
56
57static GLboolean WarnFlag = GL_FALSE;
58
59void
60_glapi_noop_enable_warnings(GLboolean enable)
61{
62 WarnFlag = enable;
63}
64
65static GLboolean
66warn(void)
67{
68 if (WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
69 return GL_TRUE;
70 else
71 return GL_FALSE;
72}
73
74
75#define KEYWORD1 static
76#define KEYWORD2
77#define NAME(func) NoOp##func
78
79#define F stderr
80
81#define DISPATCH(func, args, msg) \
82 if (warn()) { \
83 fprintf(stderr, "GL User Error: calling "); \
84 fprintf msg; \
85 fprintf(stderr, " without a current context\n"); \
86 }
87
88#define RETURN_DISPATCH(func, args, msg) \
89 if (warn()) { \
90 fprintf(stderr, "GL User Error: calling "); \
91 fprintf msg; \
92 fprintf(stderr, " without a current context\n"); \
93 } \
94 return 0
95
96#define DISPATCH_TABLE_NAME __glapi_noop_table
97#define UNUSED_TABLE_NAME __usused_noop_functions
98
99#define TABLE_ENTRY(name) (void *) NoOp##name
100
101static int NoOpUnused(void)
102{
103 if (warn()) {
104 fprintf(stderr, "GL User Error: calling extension function without a current context\n");
105 }
106 return 0;
107}
108
109#include "glapitemp.h"
110
111/***** END NO-OP DISPATCH *****/
112
113
114
115/***** BEGIN THREAD-SAFE DISPATCH *****/
116/* if we support thread-safety, build a special dispatch table for use
117 * in thread-safety mode (ThreadSafe == GL_TRUE). Each entry in the
118 * dispatch table will call _glthread_GetTSD() to get the actual dispatch
119 * table bound to the current thread, then jump through that table.
120 */
121
122#if defined(THREADS)
123
124static GLboolean ThreadSafe = GL_FALSE; /* In thread-safe mode? */
125static _glthread_TSD DispatchTSD; /* Per-thread dispatch pointer */
126static _glthread_TSD RealDispatchTSD; /* only when using override */
127static _glthread_TSD ContextTSD; /* Per-thread context pointer */
128
129
130#define KEYWORD1 static
131#define KEYWORD2 GLAPIENTRY
132#define NAME(func) _ts_##func
133
134#define DISPATCH(FUNC, ARGS, MESSAGE) \
135 struct _glapi_table *dispatch; \
136 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
137 if (!dispatch) \
138 dispatch = (struct _glapi_table *) __glapi_noop_table; \
139 (dispatch->FUNC) ARGS
140
141#define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \
142 struct _glapi_table *dispatch; \
143 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
144 if (!dispatch) \
145 dispatch = (struct _glapi_table *) __glapi_noop_table; \
146 return (dispatch->FUNC) ARGS
147
148#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
149#define UNUSED_TABLE_NAME __usused_threadsafe_functions
150
151#define TABLE_ENTRY(name) (void *) _ts_##name
152
153static int _ts_Unused(void)
154{
155 return 0;
156}
157
158#include "glapitemp.h"
159
160#endif
161
162/***** END THREAD-SAFE DISPATCH *****/
163
164
165
Brian Paul8ceb5c32000-02-24 22:14:04 +0000166struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000167struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul0f710251999-12-15 15:02:30 +0000168
Brian Paul8f91fb61999-12-17 14:51:28 +0000169/* Used when thread safety disabled */
Brian Paulf9b97d92000-01-28 20:17:42 +0000170void *_glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000171
Brian Paul0f710251999-12-15 15:02:30 +0000172
Brian Paulbb72d321999-12-16 17:31:59 +0000173static GLuint MaxDispatchOffset = sizeof(struct _glapi_table) / sizeof(void *) - 1;
Brian Paul0f710251999-12-15 15:02:30 +0000174static GLboolean GetSizeCalled = GL_FALSE;
Brian Paulfbd8f211999-11-11 01:22:25 +0000175
Brian Paulab0c8862001-01-23 23:35:47 +0000176static GLboolean DispatchOverride = GL_FALSE;
177
178
Brian Paul3c257e12001-03-28 17:19:58 +0000179/* strdup() is actually not a standard ANSI C or POSIX routine.
180 * Irix will not define it if ANSI mode is in effect.
181 */
182static char *
183str_dup(const char *str)
Randy Frankd7361e12000-03-27 21:13:58 +0000184{
Brian Paulfffb8092000-03-29 18:46:11 +0000185 char *copy;
186 copy = (char*) malloc(strlen(str) + 1);
187 if (!copy)
188 return NULL;
189 strcpy(copy, str);
190 return copy;
Randy Frankd7361e12000-03-27 21:13:58 +0000191}
192
Brian Paul7fb54ae1999-11-19 22:33:50 +0000193
Brian Paulbb72d321999-12-16 17:31:59 +0000194
195/*
196 * We should call this periodically from a function such as glXMakeCurrent
Brian Paul5104b4d2002-03-07 21:50:41 +0000197 * in order to test if multiple threads are being used.
Brian Paulbb72d321999-12-16 17:31:59 +0000198 */
199void
200_glapi_check_multithread(void)
201{
202#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000203 if (!ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000204 static unsigned long knownID;
205 static GLboolean firstCall = GL_TRUE;
206 if (firstCall) {
207 knownID = _glthread_GetID();
208 firstCall = GL_FALSE;
209 }
210 else if (knownID != _glthread_GetID()) {
Brian Paul26e14d22000-01-05 04:36:17 +0000211 ThreadSafe = GL_TRUE;
Brian Paulbb72d321999-12-16 17:31:59 +0000212 }
213 }
Brian Paul26e14d22000-01-05 04:36:17 +0000214 if (ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000215 /* make sure that this thread's dispatch pointer isn't null */
216 if (!_glapi_get_dispatch()) {
217 _glapi_set_dispatch(NULL);
218 }
219 }
220#endif
221}
222
223
224
225/*
Brian Paul8f91fb61999-12-17 14:51:28 +0000226 * Set the current context pointer for this thread.
227 * The context pointer is an opaque type which should be cast to
228 * void from the real context pointer type.
229 */
230void
Brian Paulf9b97d92000-01-28 20:17:42 +0000231_glapi_set_context(void *context)
Brian Paul8f91fb61999-12-17 14:51:28 +0000232{
233#if defined(THREADS)
Brian Paul3c27be32000-02-10 21:27:48 +0000234 _glthread_SetTSD(&ContextTSD, context);
Brian Paul26e14d22000-01-05 04:36:17 +0000235 if (ThreadSafe)
Brian Paulf9b97d92000-01-28 20:17:42 +0000236 _glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000237 else
Brian Paulf9b97d92000-01-28 20:17:42 +0000238 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000239#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000240 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000241#endif
242}
243
244
245
246/*
247 * Get the current context pointer for this thread.
248 * The context pointer is an opaque type which should be cast from
249 * void to the real context pointer type.
250 */
251void *
Brian Paulf9b97d92000-01-28 20:17:42 +0000252_glapi_get_context(void)
Brian Paul8f91fb61999-12-17 14:51:28 +0000253{
254#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000255 if (ThreadSafe) {
Brian Paul8f91fb61999-12-17 14:51:28 +0000256 return _glthread_GetTSD(&ContextTSD);
257 }
258 else {
Brian Paulf9b97d92000-01-28 20:17:42 +0000259 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000260 }
261#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000262 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000263#endif
264}
265
266
267
268/*
Brian Paul7fb54ae1999-11-19 22:33:50 +0000269 * Set the global or per-thread dispatch table pointer.
270 */
271void
272_glapi_set_dispatch(struct _glapi_table *dispatch)
273{
274 if (!dispatch) {
275 /* use the no-op functions */
Brian Paul8ceb5c32000-02-24 22:14:04 +0000276 dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000277 }
278#ifdef DEBUG
279 else {
280 _glapi_check_table(dispatch);
281 }
282#endif
283
284#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000285 if (DispatchOverride) {
286 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000287 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000288 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000289 else
Brian Paulab0c8862001-01-23 23:35:47 +0000290 _glapi_RealDispatch = dispatch;
Brian Paul3b18a362000-09-26 15:27:20 +0000291 }
292 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000293 /* normal operation */
Brian Paul3b18a362000-09-26 15:27:20 +0000294 _glthread_SetTSD(&DispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000295 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000296 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000297 else
298 _glapi_Dispatch = dispatch;
299 }
Brian Paul3a71d052000-09-05 20:17:37 +0000300#else /*THREADS*/
Brian Paulab0c8862001-01-23 23:35:47 +0000301 if (DispatchOverride) {
302 _glapi_RealDispatch = dispatch;
303 }
304 else {
305 _glapi_Dispatch = dispatch;
306 }
Brian Paul3a71d052000-09-05 20:17:37 +0000307#endif /*THREADS*/
Brian Paul7fb54ae1999-11-19 22:33:50 +0000308}
309
310
Brian Paulbb72d321999-12-16 17:31:59 +0000311
Brian Paul7fb54ae1999-11-19 22:33:50 +0000312/*
Brian Paulbb72d321999-12-16 17:31:59 +0000313 * Return pointer to current dispatch table for calling thread.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000314 */
315struct _glapi_table *
316_glapi_get_dispatch(void)
317{
318#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000319 if (ThreadSafe) {
Brian Paulab0c8862001-01-23 23:35:47 +0000320 if (DispatchOverride) {
321 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
322 }
323 else {
324 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
325 }
Brian Paulbb72d321999-12-16 17:31:59 +0000326 }
Brian Paul590d3471999-12-17 12:20:23 +0000327 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000328 if (DispatchOverride) {
329 assert(_glapi_RealDispatch);
330 return _glapi_RealDispatch;
331 }
332 else {
333 assert(_glapi_Dispatch);
334 return _glapi_Dispatch;
335 }
Brian Paul590d3471999-12-17 12:20:23 +0000336 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000337#else
Brian Paulc2319b42000-01-17 19:28:31 +0000338 return _glapi_Dispatch;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000339#endif
340}
341
342
Brian Paulab0c8862001-01-23 23:35:47 +0000343/*
344 * Notes on dispatch overrride:
345 *
346 * Dispatch override allows an external agent to hook into the GL dispatch
347 * mechanism before execution goes into the core rendering library. For
348 * example, a trace mechanism would insert itself as an overrider, print
349 * logging info for each GL function, then dispatch to the real GL function.
350 *
351 * libGLS (GL Stream library) is another agent that might use override.
352 *
353 * We don't allow more than one layer of overriding at this time.
354 * In the future we may allow nested/layered override. In that case
355 * _glapi_begin_dispatch_override() will return an override layer,
356 * _glapi_end_dispatch_override(layer) will remove an override layer
357 * and _glapi_get_override_dispatch(layer) will return the dispatch
358 * table for a given override layer. layer = 0 will be the "real"
359 * dispatch table.
360 */
361
362/*
363 * Return: dispatch override layer number.
364 */
365int
366_glapi_begin_dispatch_override(struct _glapi_table *override)
Brian Paul3a71d052000-09-05 20:17:37 +0000367{
Brian Paulab0c8862001-01-23 23:35:47 +0000368 struct _glapi_table *real = _glapi_get_dispatch();
369
370 assert(!DispatchOverride); /* can't nest at this time */
371 DispatchOverride = GL_TRUE;
372
373 _glapi_set_dispatch(real);
Brian Paul3a71d052000-09-05 20:17:37 +0000374
375#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000376 _glthread_SetTSD(&DispatchTSD, (void *) override);
377 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000378 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000379 else
380 _glapi_Dispatch = override;
381#else
382 _glapi_Dispatch = override;
383#endif
384 return 1;
385}
386
387
388void
389_glapi_end_dispatch_override(int layer)
390{
391 struct _glapi_table *real = _glapi_get_dispatch();
392 (void) layer;
393 DispatchOverride = GL_FALSE;
394 _glapi_set_dispatch(real);
395 /* the rest of this isn't needed, just play it safe */
396#if defined(THREADS)
397 _glthread_SetTSD(&RealDispatchTSD, NULL);
398#endif
399 _glapi_RealDispatch = NULL;
400}
401
402
403struct _glapi_table *
404_glapi_get_override_dispatch(int layer)
405{
406 if (layer == 0) {
407 return _glapi_get_dispatch();
Brian Paul3a71d052000-09-05 20:17:37 +0000408 }
409 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000410 if (DispatchOverride) {
411#if defined(THREADS)
412 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
Brian Paul3a71d052000-09-05 20:17:37 +0000413#else
Brian Paulab0c8862001-01-23 23:35:47 +0000414 return _glapi_Dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000415#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000416 }
417 else {
418 return NULL;
419 }
420 }
Brian Paul3a71d052000-09-05 20:17:37 +0000421}
Brian Paulab0c8862001-01-23 23:35:47 +0000422
Brian Paul3a71d052000-09-05 20:17:37 +0000423
Brian Paul91bcefa1999-11-27 21:30:40 +0000424
425/*
426 * Return size of dispatch table struct as number of functions (or
427 * slots).
428 */
429GLuint
430_glapi_get_dispatch_table_size(void)
431{
Brian Paul0f710251999-12-15 15:02:30 +0000432 /* return sizeof(struct _glapi_table) / sizeof(void *);*/
433 GetSizeCalled = GL_TRUE;
434 return MaxDispatchOffset + 1;
Brian Paul91bcefa1999-11-27 21:30:40 +0000435}
436
437
438
Brian Paul7fb54ae1999-11-19 22:33:50 +0000439/*
440 * Get API dispatcher version string.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000441 */
442const char *
443_glapi_get_version(void)
444{
Brian Paulab0c8862001-01-23 23:35:47 +0000445 return "20010116"; /* YYYYMMDD */
Brian Paul7fb54ae1999-11-19 22:33:50 +0000446}
447
448
Brian Paul959f8022000-03-19 01:10:11 +0000449struct name_address_offset {
450 const char *Name;
451 GLvoid *Address;
452 GLuint Offset;
453};
454
Brian Paul0c239fc1999-12-16 12:38:11 +0000455
Brian Paulb5fd8862001-11-18 22:48:11 +0000456/* The code in this file is auto-generated */
457#include "glprocs.h"
Brian Paul7fb54ae1999-11-19 22:33:50 +0000458
Brian Paul959f8022000-03-19 01:10:11 +0000459
460
461/*
462 * Return dispatch table offset of the named static (built-in) function.
463 * Return -1 if function not found.
464 */
465static GLint
466get_static_proc_offset(const char *funcName)
467{
468 GLuint i;
469 for (i = 0; static_functions[i].Name; i++) {
470 if (strcmp(static_functions[i].Name, funcName) == 0) {
Brian Paul94666c42001-09-14 02:48:53 +0000471 return static_functions[i].Offset;
Brian Paul959f8022000-03-19 01:10:11 +0000472 }
473 }
474 return -1;
475}
476
477
478/*
479 * Return dispatch function address the named static (built-in) function.
480 * Return NULL if function not found.
481 */
482static GLvoid *
483get_static_proc_address(const char *funcName)
484{
Brian Paul9c7ca852000-10-19 20:13:12 +0000485 GLint i;
486 for (i = 0; static_functions[i].Name; i++) {
487 if (strcmp(static_functions[i].Name, funcName) == 0) {
488 return static_functions[i].Address;
489 }
490 }
491 return NULL;
Brian Paul959f8022000-03-19 01:10:11 +0000492}
493
494
495
496/**********************************************************************
497 * Extension function management.
498 */
499
500
501#define MAX_EXTENSION_FUNCS 1000
502
503static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
504static GLuint NumExtEntryPoints = 0;
505
davem694a497e62001-06-06 22:55:28 +0000506#ifdef USE_SPARC_ASM
507extern void __glapi_sparc_icache_flush(unsigned int *);
508#endif
Brian Paul959f8022000-03-19 01:10:11 +0000509
510/*
511 * Generate a dispatch function (entrypoint) which jumps through
512 * the given slot number (offset) in the current dispatch table.
513 * We need assembly language in order to accomplish this.
514 */
515static void *
516generate_entrypoint(GLuint functionOffset)
517{
518#if defined(USE_X86_ASM)
519 /*
520 * This x86 code contributed by Josh Vanderhoof.
521 *
522 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
523 * 00 01 02 03 04
524 * 5: 85 c0 testl %eax,%eax
525 * 05 06
526 * 7: 74 06 je f <entrypoint+0xf>
527 * 07 08
528 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
529 * 09 0a 0b 0c 0d 0e
530 * f: e8 fc ff ff ff call __glapi_get_dispatch
531 * 0f 10 11 12 13
532 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
533 * 14 15 16 17 18 19
534 */
535 static const unsigned char temp[] = {
536 0xa1, 0x00, 0x00, 0x00, 0x00,
537 0x85, 0xc0,
538 0x74, 0x06,
539 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
540 0xe8, 0x00, 0x00, 0x00, 0x00,
541 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
542 };
543 unsigned char *code = malloc(sizeof(temp));
544 unsigned int next_insn;
545 if (code) {
546 memcpy(code, temp, sizeof(temp));
547
548 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
549 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
550 next_insn = (unsigned int)(code + 0x14);
551 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
552 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
553 }
554 return code;
davem69775355a2001-06-05 23:54:00 +0000555#elif defined(USE_SPARC_ASM)
556
557#ifdef __sparc_v9__
558 static const unsigned int insn_template[] = {
559 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
560 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
561 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
562 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
563 0x8528b020, /* sllx %g2, 32, %g2 */
564 0xc2584002, /* ldx [%g1 + %g2], %g1 */
565 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
566 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
567 0xc6584002, /* ldx [%g1 + %g2], %g3 */
568 0x81c0c000, /* jmpl %g3, %g0 */
569 0x01000000 /* nop */
570 };
571#else
572 static const unsigned int insn_template[] = {
573 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
574 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
575 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
576 0x81c0c000, /* jmpl %g3, %g0 */
577 0x01000000 /* nop */
578 };
579#endif
580 unsigned int *code = malloc(sizeof(insn_template));
581 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
582 if (code) {
583 memcpy(code, insn_template, sizeof(insn_template));
584
585#ifdef __sparc_v9__
586 code[0] |= (glapi_addr >> (32 + 10));
587 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
davem694a497e62001-06-06 22:55:28 +0000588 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000589 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
590 code[3] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000591 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000592 code[6] |= ((functionOffset * 8) >> 10);
593 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000594 __glapi_sparc_icache_flush(&code[6]);
davem69775355a2001-06-05 23:54:00 +0000595#else
596 code[0] |= (glapi_addr >> 10);
597 code[1] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000598 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000599 code[2] |= (functionOffset * 4);
davem694a497e62001-06-06 22:55:28 +0000600 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000601#endif
602 }
603 return code;
Brian Paul959f8022000-03-19 01:10:11 +0000604#else
605 return NULL;
606#endif
607}
608
609
610
611/*
612 * Add a new extension function entrypoint.
613 * Return: GL_TRUE = success or GL_FALSE = failure
614 */
615GLboolean
616_glapi_add_entrypoint(const char *funcName, GLuint offset)
617{
Brian Paul959f8022000-03-19 01:10:11 +0000618 /* first check if the named function is already statically present */
619 {
620 GLint index = get_static_proc_offset(funcName);
621 if (index >= 0) {
Brian Paulb51b0a82001-03-07 05:06:11 +0000622 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
Brian Paul959f8022000-03-19 01:10:11 +0000623 }
624 }
625
626 {
627 /* make sure this offset/name pair is legal */
628 const char *name = _glapi_get_proc_name(offset);
629 if (name && strcmp(name, funcName) != 0)
630 return GL_FALSE; /* bad name! */
631 }
632
633 {
634 /* be sure index and name match known data */
635 GLuint i;
636 for (i = 0; i < NumExtEntryPoints; i++) {
637 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
638 /* function already registered with api */
639 if (ExtEntryTable[i].Offset == offset) {
640 return GL_TRUE; /* offsets match */
641 }
642 else {
643 return GL_FALSE; /* bad offset! */
644 }
645 }
646 }
647
Brian Paul2c3a6202000-05-24 17:53:30 +0000648 /* Make sure we don't try to add a new entrypoint after someone
649 * has already called _glapi_get_dispatch_table_size()! If that's
650 * happened the caller's information would become out of date.
651 */
652 if (GetSizeCalled)
653 return GL_FALSE;
654
Brian Paul959f8022000-03-19 01:10:11 +0000655 /* make sure we have space */
656 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS) {
657 return GL_FALSE;
658 }
659 else {
660 void *entrypoint = generate_entrypoint(offset);
661 if (!entrypoint)
662 return GL_FALSE;
663
Brian Paulfffb8092000-03-29 18:46:11 +0000664 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
Brian Paul959f8022000-03-19 01:10:11 +0000665 ExtEntryTable[NumExtEntryPoints].Offset = offset;
666 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
667 NumExtEntryPoints++;
668
669 if (offset > MaxDispatchOffset)
670 MaxDispatchOffset = offset;
671
672 return GL_TRUE; /* success */
673 }
674 }
675
676 /* should never get here, but play it safe */
677 return GL_FALSE;
678}
679
680
681
682#if 0000 /* prototype code for dynamic extension slot allocation */
683
684static int NextFreeOffset = 409; /*XXX*/
685#define MAX_DISPATCH_TABLE_SIZE 1000
686
687/*
688 * Dynamically allocate a dispatch slot for an extension entrypoint
689 * and generate the assembly language dispatch stub.
690 * Return the dispatch offset for the function or -1 if no room or error.
691 */
692GLint
693_glapi_add_entrypoint2(const char *funcName)
694{
695 int offset;
696
697 /* first see if extension func is already known */
698 offset = _glapi_get_proc_offset(funcName);
699 if (offset >= 0)
700 return offset;
701
702 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS
703 && NextFreeOffset < MAX_DISPATCH_TABLE_SIZE) {
704 void *entryPoint;
705 offset = NextFreeOffset;
706 entryPoint = generate_entrypoint(offset);
707 if (entryPoint) {
708 NextFreeOffset++;
Brian Paulfffb8092000-03-29 18:46:11 +0000709 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
Brian Paul959f8022000-03-19 01:10:11 +0000710 ExtEntryTable[NumExtEntryPoints].Offset = offset;
711 ExtEntryTable[NumExtEntryPoints].Address = entryPoint;
712 NumExtEntryPoints++;
713 return offset;
714 }
715 }
716 return -1;
717}
718
719#endif
720
721
722
723/*
724 * Return offset of entrypoint for named function within dispatch table.
725 */
726GLint
727_glapi_get_proc_offset(const char *funcName)
728{
729 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000730 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000731 for (i = 0; i < NumExtEntryPoints; i++) {
732 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
733 return ExtEntryTable[i].Offset;
734 }
735 }
736
737 /* search static functions */
738 return get_static_proc_offset(funcName);
739}
740
741
742
743/*
744 * Return entrypoint for named function.
745 */
746const GLvoid *
747_glapi_get_proc_address(const char *funcName)
748{
749 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000750 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000751 for (i = 0; i < NumExtEntryPoints; i++) {
752 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
753 return ExtEntryTable[i].Address;
754 }
755 }
756
757 /* search static functions */
758 return get_static_proc_address(funcName);
759}
760
761
762
763
764/*
765 * Return the name of the function at the given dispatch offset.
766 * This is only intended for debugging.
767 */
768const char *
769_glapi_get_proc_name(GLuint offset)
770{
771 const GLuint n = sizeof(static_functions) / sizeof(struct name_address_offset);
772 GLuint i;
773 for (i = 0; i < n; i++) {
774 if (static_functions[i].Offset == offset)
775 return static_functions[i].Name;
776 }
777
778 /* search added extension functions */
779 for (i = 0; i < NumExtEntryPoints; i++) {
780 if (ExtEntryTable[i].Offset == offset) {
781 return ExtEntryTable[i].Name;
782 }
783 }
784 return NULL;
785}
786
787
788
789/*
790 * Make sure there are no NULL pointers in the given dispatch table.
Brian Paul5104b4d2002-03-07 21:50:41 +0000791 * Intended for debugging purposes.
Brian Paul959f8022000-03-19 01:10:11 +0000792 */
793void
794_glapi_check_table(const struct _glapi_table *table)
795{
Brian Paul5104b4d2002-03-07 21:50:41 +0000796#ifdef DEBUG
Brian Paul959f8022000-03-19 01:10:11 +0000797 const GLuint entries = _glapi_get_dispatch_table_size();
798 const void **tab = (const void **) table;
799 GLuint i;
800 for (i = 1; i < entries; i++) {
801 assert(tab[i]);
802 }
803
Brian Paul959f8022000-03-19 01:10:11 +0000804 /* Do some spot checks to be sure that the dispatch table
805 * slots are assigned correctly.
806 */
807 {
808 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
809 char *BeginFunc = (char*) &table->Begin;
810 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
811 assert(BeginOffset == _gloffset_Begin);
812 assert(BeginOffset == offset);
813 }
814 {
815 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
816 char *viewportFunc = (char*) &table->Viewport;
817 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
818 assert(viewportOffset == _gloffset_Viewport);
819 assert(viewportOffset == offset);
820 }
821 {
822 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
823 char *VertexPointerFunc = (char*) &table->VertexPointer;
824 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
825 assert(VertexPointerOffset == _gloffset_VertexPointer);
826 assert(VertexPointerOffset == offset);
827 }
828 {
829 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
830 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
831 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
832 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
833 assert(ResetMinMaxOffset == offset);
834 }
835 {
836 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
837 char *blendColorFunc = (char*) &table->BlendColor;
838 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
839 assert(blendColorOffset == _gloffset_BlendColor);
840 assert(blendColorOffset == offset);
841 }
842 {
843 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
844 char *istextureFunc = (char*) &table->IsTextureEXT;
845 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
846 assert(istextureOffset == _gloffset_IsTextureEXT);
847 assert(istextureOffset == offset);
848 }
Brian Paula14cbff2000-10-27 18:31:21 +0000849 {
850 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
851 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
852 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
853 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
854 assert(secondaryColor3fOffset == offset);
855 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
856 }
Brian Paul91d6f122002-05-29 15:23:16 +0000857 {
858 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
859 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
860 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
861 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
862 assert(pointParameterivOffset == offset);
863 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
864 }
Brian Paul959f8022000-03-19 01:10:11 +0000865#endif
866}