blob: 78f0553427436d42b45090ec391d88425b3f993c [file] [log] [blame]
Brian Paul4e9676f2002-06-29 19:48:15 +00001/* $Id: glapi.c,v 1.63 2002/06/29 19:48: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 *
Brian Paul4e9676f2002-06-29 19:48:15 +000040 * NOTE: 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 Paul4e9676f2002-06-29 19:48:15 +000045 * 2002/06/28 - added _glapi_set_warning_func(), Mesa 4.1.
Brian Paul7e1161b1999-11-25 18:17:04 +000046 */
47
48
49
Brian Paul3c27be32000-02-10 21:27:48 +000050#include "glheader.h"
Brian Paulfbd8f211999-11-11 01:22:25 +000051#include "glapi.h"
Brian Paul0c239fc1999-12-16 12:38:11 +000052#include "glapioffsets.h"
53#include "glapitable.h"
Brian Paul9f943992000-01-28 19:03:33 +000054#include "glthread.h"
Brian Paulbb72d321999-12-16 17:31:59 +000055
Brian Paul3c257e12001-03-28 17:19:58 +000056/***** BEGIN NO-OP DISPATCH *****/
57
58static GLboolean WarnFlag = GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000059static _glapi_warning_func warning_func;
Brian Paul3c257e12001-03-28 17:19:58 +000060
Brian Paul4e9676f2002-06-29 19:48:15 +000061
62/*
63 * Enable/disable printing of warning messages.
64 */
Brian Paul3c257e12001-03-28 17:19:58 +000065void
66_glapi_noop_enable_warnings(GLboolean enable)
67{
68 WarnFlag = enable;
69}
70
Brian Paul4e9676f2002-06-29 19:48:15 +000071/*
72 * Register a callback function for reporting errors.
73 */
74void
75_glapi_set_warning_func( _glapi_warning_func func )
76{
77 warning_func = func;
78}
79
Brian Paul3c257e12001-03-28 17:19:58 +000080static GLboolean
81warn(void)
82{
Brian Paul4e9676f2002-06-29 19:48:15 +000083 if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
84 && warning_func) {
Brian Paul3c257e12001-03-28 17:19:58 +000085 return GL_TRUE;
Brian Paul4e9676f2002-06-29 19:48:15 +000086 }
87 else {
Brian Paul3c257e12001-03-28 17:19:58 +000088 return GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000089 }
Brian Paul3c257e12001-03-28 17:19:58 +000090}
91
92
93#define KEYWORD1 static
94#define KEYWORD2
95#define NAME(func) NoOp##func
96
Brian Paul4e9676f2002-06-29 19:48:15 +000097#define F NULL
Brian Paul3c257e12001-03-28 17:19:58 +000098
Brian Paul4e9676f2002-06-29 19:48:15 +000099#define DISPATCH(func, args, msg) \
100 if (warn()) { \
101 warning_func(NULL, "GL User Error: called without context:"); \
102 warning_func msg; \
Brian Paul3c257e12001-03-28 17:19:58 +0000103 }
104
Brian Paul4e9676f2002-06-29 19:48:15 +0000105#define RETURN_DISPATCH(func, args, msg) \
106 if (warn()) { \
107 warning_func(NULL, "GL User Error: called without context:"); \
108 warning_func msg; \
109 } \
Brian Paul3c257e12001-03-28 17:19:58 +0000110 return 0
111
112#define DISPATCH_TABLE_NAME __glapi_noop_table
113#define UNUSED_TABLE_NAME __usused_noop_functions
114
115#define TABLE_ENTRY(name) (void *) NoOp##name
116
117static int NoOpUnused(void)
118{
119 if (warn()) {
Brian Paul4e9676f2002-06-29 19:48:15 +0000120 warning_func(NULL, "GL User Error: calling extension function without a current context\n");
Brian Paul3c257e12001-03-28 17:19:58 +0000121 }
122 return 0;
123}
124
125#include "glapitemp.h"
126
127/***** END NO-OP DISPATCH *****/
128
129
130
131/***** BEGIN THREAD-SAFE DISPATCH *****/
132/* if we support thread-safety, build a special dispatch table for use
133 * in thread-safety mode (ThreadSafe == GL_TRUE). Each entry in the
134 * dispatch table will call _glthread_GetTSD() to get the actual dispatch
135 * table bound to the current thread, then jump through that table.
136 */
137
138#if defined(THREADS)
139
140static GLboolean ThreadSafe = GL_FALSE; /* In thread-safe mode? */
141static _glthread_TSD DispatchTSD; /* Per-thread dispatch pointer */
142static _glthread_TSD RealDispatchTSD; /* only when using override */
143static _glthread_TSD ContextTSD; /* Per-thread context pointer */
144
145
146#define KEYWORD1 static
147#define KEYWORD2 GLAPIENTRY
148#define NAME(func) _ts_##func
149
150#define DISPATCH(FUNC, ARGS, MESSAGE) \
151 struct _glapi_table *dispatch; \
152 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
153 if (!dispatch) \
154 dispatch = (struct _glapi_table *) __glapi_noop_table; \
155 (dispatch->FUNC) ARGS
156
157#define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \
158 struct _glapi_table *dispatch; \
159 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
160 if (!dispatch) \
161 dispatch = (struct _glapi_table *) __glapi_noop_table; \
162 return (dispatch->FUNC) ARGS
163
164#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
165#define UNUSED_TABLE_NAME __usused_threadsafe_functions
166
167#define TABLE_ENTRY(name) (void *) _ts_##name
168
169static int _ts_Unused(void)
170{
171 return 0;
172}
173
174#include "glapitemp.h"
175
176#endif
177
178/***** END THREAD-SAFE DISPATCH *****/
179
180
181
Brian Paul8ceb5c32000-02-24 22:14:04 +0000182struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000183struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul0f710251999-12-15 15:02:30 +0000184
Brian Paul8f91fb61999-12-17 14:51:28 +0000185/* Used when thread safety disabled */
Brian Paulf9b97d92000-01-28 20:17:42 +0000186void *_glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000187
Brian Paul0f710251999-12-15 15:02:30 +0000188
Brian Paulbb72d321999-12-16 17:31:59 +0000189static GLuint MaxDispatchOffset = sizeof(struct _glapi_table) / sizeof(void *) - 1;
Brian Paul0f710251999-12-15 15:02:30 +0000190static GLboolean GetSizeCalled = GL_FALSE;
Brian Paulfbd8f211999-11-11 01:22:25 +0000191
Brian Paulab0c8862001-01-23 23:35:47 +0000192static GLboolean DispatchOverride = GL_FALSE;
193
194
Brian Paul3c257e12001-03-28 17:19:58 +0000195/* strdup() is actually not a standard ANSI C or POSIX routine.
196 * Irix will not define it if ANSI mode is in effect.
197 */
198static char *
199str_dup(const char *str)
Randy Frankd7361e12000-03-27 21:13:58 +0000200{
Brian Paulfffb8092000-03-29 18:46:11 +0000201 char *copy;
202 copy = (char*) malloc(strlen(str) + 1);
203 if (!copy)
204 return NULL;
205 strcpy(copy, str);
206 return copy;
Randy Frankd7361e12000-03-27 21:13:58 +0000207}
208
Brian Paul7fb54ae1999-11-19 22:33:50 +0000209
Brian Paulbb72d321999-12-16 17:31:59 +0000210
211/*
212 * We should call this periodically from a function such as glXMakeCurrent
Brian Paul5104b4d2002-03-07 21:50:41 +0000213 * in order to test if multiple threads are being used.
Brian Paulbb72d321999-12-16 17:31:59 +0000214 */
215void
216_glapi_check_multithread(void)
217{
218#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000219 if (!ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000220 static unsigned long knownID;
221 static GLboolean firstCall = GL_TRUE;
222 if (firstCall) {
223 knownID = _glthread_GetID();
224 firstCall = GL_FALSE;
225 }
226 else if (knownID != _glthread_GetID()) {
Brian Paul26e14d22000-01-05 04:36:17 +0000227 ThreadSafe = GL_TRUE;
Brian Paulbb72d321999-12-16 17:31:59 +0000228 }
229 }
Brian Paul26e14d22000-01-05 04:36:17 +0000230 if (ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000231 /* make sure that this thread's dispatch pointer isn't null */
232 if (!_glapi_get_dispatch()) {
233 _glapi_set_dispatch(NULL);
234 }
235 }
236#endif
237}
238
239
240
241/*
Brian Paul8f91fb61999-12-17 14:51:28 +0000242 * Set the current context pointer for this thread.
243 * The context pointer is an opaque type which should be cast to
244 * void from the real context pointer type.
245 */
246void
Brian Paulf9b97d92000-01-28 20:17:42 +0000247_glapi_set_context(void *context)
Brian Paul8f91fb61999-12-17 14:51:28 +0000248{
249#if defined(THREADS)
Brian Paul3c27be32000-02-10 21:27:48 +0000250 _glthread_SetTSD(&ContextTSD, context);
Brian Paul26e14d22000-01-05 04:36:17 +0000251 if (ThreadSafe)
Brian Paulf9b97d92000-01-28 20:17:42 +0000252 _glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000253 else
Brian Paulf9b97d92000-01-28 20:17:42 +0000254 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000255#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000256 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000257#endif
258}
259
260
261
262/*
263 * Get the current context pointer for this thread.
264 * The context pointer is an opaque type which should be cast from
265 * void to the real context pointer type.
266 */
267void *
Brian Paulf9b97d92000-01-28 20:17:42 +0000268_glapi_get_context(void)
Brian Paul8f91fb61999-12-17 14:51:28 +0000269{
270#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000271 if (ThreadSafe) {
Brian Paul8f91fb61999-12-17 14:51:28 +0000272 return _glthread_GetTSD(&ContextTSD);
273 }
274 else {
Brian Paulf9b97d92000-01-28 20:17:42 +0000275 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000276 }
277#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000278 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000279#endif
280}
281
282
283
284/*
Brian Paul7fb54ae1999-11-19 22:33:50 +0000285 * Set the global or per-thread dispatch table pointer.
286 */
287void
288_glapi_set_dispatch(struct _glapi_table *dispatch)
289{
290 if (!dispatch) {
291 /* use the no-op functions */
Brian Paul8ceb5c32000-02-24 22:14:04 +0000292 dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000293 }
294#ifdef DEBUG
295 else {
296 _glapi_check_table(dispatch);
297 }
298#endif
299
300#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000301 if (DispatchOverride) {
302 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000303 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000304 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000305 else
Brian Paulab0c8862001-01-23 23:35:47 +0000306 _glapi_RealDispatch = dispatch;
Brian Paul3b18a362000-09-26 15:27:20 +0000307 }
308 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000309 /* normal operation */
Brian Paul3b18a362000-09-26 15:27:20 +0000310 _glthread_SetTSD(&DispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000311 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000312 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000313 else
314 _glapi_Dispatch = dispatch;
315 }
Brian Paul3a71d052000-09-05 20:17:37 +0000316#else /*THREADS*/
Brian Paulab0c8862001-01-23 23:35:47 +0000317 if (DispatchOverride) {
318 _glapi_RealDispatch = dispatch;
319 }
320 else {
321 _glapi_Dispatch = dispatch;
322 }
Brian Paul3a71d052000-09-05 20:17:37 +0000323#endif /*THREADS*/
Brian Paul7fb54ae1999-11-19 22:33:50 +0000324}
325
326
Brian Paulbb72d321999-12-16 17:31:59 +0000327
Brian Paul7fb54ae1999-11-19 22:33:50 +0000328/*
Brian Paulbb72d321999-12-16 17:31:59 +0000329 * Return pointer to current dispatch table for calling thread.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000330 */
331struct _glapi_table *
332_glapi_get_dispatch(void)
333{
334#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000335 if (ThreadSafe) {
Brian Paulab0c8862001-01-23 23:35:47 +0000336 if (DispatchOverride) {
337 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
338 }
339 else {
340 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
341 }
Brian Paulbb72d321999-12-16 17:31:59 +0000342 }
Brian Paul590d3471999-12-17 12:20:23 +0000343 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000344 if (DispatchOverride) {
345 assert(_glapi_RealDispatch);
346 return _glapi_RealDispatch;
347 }
348 else {
349 assert(_glapi_Dispatch);
350 return _glapi_Dispatch;
351 }
Brian Paul590d3471999-12-17 12:20:23 +0000352 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000353#else
Brian Paulc2319b42000-01-17 19:28:31 +0000354 return _glapi_Dispatch;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000355#endif
356}
357
358
Brian Paulab0c8862001-01-23 23:35:47 +0000359/*
360 * Notes on dispatch overrride:
361 *
362 * Dispatch override allows an external agent to hook into the GL dispatch
363 * mechanism before execution goes into the core rendering library. For
364 * example, a trace mechanism would insert itself as an overrider, print
365 * logging info for each GL function, then dispatch to the real GL function.
366 *
367 * libGLS (GL Stream library) is another agent that might use override.
368 *
369 * We don't allow more than one layer of overriding at this time.
370 * In the future we may allow nested/layered override. In that case
371 * _glapi_begin_dispatch_override() will return an override layer,
372 * _glapi_end_dispatch_override(layer) will remove an override layer
373 * and _glapi_get_override_dispatch(layer) will return the dispatch
374 * table for a given override layer. layer = 0 will be the "real"
375 * dispatch table.
376 */
377
378/*
379 * Return: dispatch override layer number.
380 */
381int
382_glapi_begin_dispatch_override(struct _glapi_table *override)
Brian Paul3a71d052000-09-05 20:17:37 +0000383{
Brian Paulab0c8862001-01-23 23:35:47 +0000384 struct _glapi_table *real = _glapi_get_dispatch();
385
386 assert(!DispatchOverride); /* can't nest at this time */
387 DispatchOverride = GL_TRUE;
388
389 _glapi_set_dispatch(real);
Brian Paul3a71d052000-09-05 20:17:37 +0000390
391#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000392 _glthread_SetTSD(&DispatchTSD, (void *) override);
393 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000394 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000395 else
396 _glapi_Dispatch = override;
397#else
398 _glapi_Dispatch = override;
399#endif
400 return 1;
401}
402
403
404void
405_glapi_end_dispatch_override(int layer)
406{
407 struct _glapi_table *real = _glapi_get_dispatch();
408 (void) layer;
409 DispatchOverride = GL_FALSE;
410 _glapi_set_dispatch(real);
411 /* the rest of this isn't needed, just play it safe */
412#if defined(THREADS)
413 _glthread_SetTSD(&RealDispatchTSD, NULL);
414#endif
415 _glapi_RealDispatch = NULL;
416}
417
418
419struct _glapi_table *
420_glapi_get_override_dispatch(int layer)
421{
422 if (layer == 0) {
423 return _glapi_get_dispatch();
Brian Paul3a71d052000-09-05 20:17:37 +0000424 }
425 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000426 if (DispatchOverride) {
427#if defined(THREADS)
428 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
Brian Paul3a71d052000-09-05 20:17:37 +0000429#else
Brian Paulab0c8862001-01-23 23:35:47 +0000430 return _glapi_Dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000431#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000432 }
433 else {
434 return NULL;
435 }
436 }
Brian Paul3a71d052000-09-05 20:17:37 +0000437}
Brian Paulab0c8862001-01-23 23:35:47 +0000438
Brian Paul3a71d052000-09-05 20:17:37 +0000439
Brian Paul91bcefa1999-11-27 21:30:40 +0000440
441/*
442 * Return size of dispatch table struct as number of functions (or
443 * slots).
444 */
445GLuint
446_glapi_get_dispatch_table_size(void)
447{
Brian Paul0f710251999-12-15 15:02:30 +0000448 /* return sizeof(struct _glapi_table) / sizeof(void *);*/
449 GetSizeCalled = GL_TRUE;
450 return MaxDispatchOffset + 1;
Brian Paul91bcefa1999-11-27 21:30:40 +0000451}
452
453
454
Brian Paul7fb54ae1999-11-19 22:33:50 +0000455/*
456 * Get API dispatcher version string.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000457 */
458const char *
459_glapi_get_version(void)
460{
Brian Paul4e9676f2002-06-29 19:48:15 +0000461 return "20020628"; /* YYYYMMDD */
Brian Paul7fb54ae1999-11-19 22:33:50 +0000462}
463
464
Brian Paul959f8022000-03-19 01:10:11 +0000465struct name_address_offset {
466 const char *Name;
467 GLvoid *Address;
468 GLuint Offset;
469};
470
Brian Paul0c239fc1999-12-16 12:38:11 +0000471
Brian Paulb5fd8862001-11-18 22:48:11 +0000472/* The code in this file is auto-generated */
473#include "glprocs.h"
Brian Paul7fb54ae1999-11-19 22:33:50 +0000474
Brian Paul959f8022000-03-19 01:10:11 +0000475
476
477/*
478 * Return dispatch table offset of the named static (built-in) function.
479 * Return -1 if function not found.
480 */
481static GLint
482get_static_proc_offset(const char *funcName)
483{
484 GLuint i;
485 for (i = 0; static_functions[i].Name; i++) {
486 if (strcmp(static_functions[i].Name, funcName) == 0) {
Brian Paul94666c42001-09-14 02:48:53 +0000487 return static_functions[i].Offset;
Brian Paul959f8022000-03-19 01:10:11 +0000488 }
489 }
490 return -1;
491}
492
493
494/*
495 * Return dispatch function address the named static (built-in) function.
496 * Return NULL if function not found.
497 */
498static GLvoid *
499get_static_proc_address(const char *funcName)
500{
Brian Paul9c7ca852000-10-19 20:13:12 +0000501 GLint i;
502 for (i = 0; static_functions[i].Name; i++) {
503 if (strcmp(static_functions[i].Name, funcName) == 0) {
504 return static_functions[i].Address;
505 }
506 }
507 return NULL;
Brian Paul959f8022000-03-19 01:10:11 +0000508}
509
510
511
512/**********************************************************************
513 * Extension function management.
514 */
515
516
517#define MAX_EXTENSION_FUNCS 1000
518
519static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
520static GLuint NumExtEntryPoints = 0;
521
davem694a497e62001-06-06 22:55:28 +0000522#ifdef USE_SPARC_ASM
523extern void __glapi_sparc_icache_flush(unsigned int *);
524#endif
Brian Paul959f8022000-03-19 01:10:11 +0000525
526/*
527 * Generate a dispatch function (entrypoint) which jumps through
528 * the given slot number (offset) in the current dispatch table.
529 * We need assembly language in order to accomplish this.
530 */
531static void *
532generate_entrypoint(GLuint functionOffset)
533{
534#if defined(USE_X86_ASM)
535 /*
536 * This x86 code contributed by Josh Vanderhoof.
537 *
538 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
539 * 00 01 02 03 04
540 * 5: 85 c0 testl %eax,%eax
541 * 05 06
542 * 7: 74 06 je f <entrypoint+0xf>
543 * 07 08
544 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
545 * 09 0a 0b 0c 0d 0e
546 * f: e8 fc ff ff ff call __glapi_get_dispatch
547 * 0f 10 11 12 13
548 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
549 * 14 15 16 17 18 19
550 */
551 static const unsigned char temp[] = {
552 0xa1, 0x00, 0x00, 0x00, 0x00,
553 0x85, 0xc0,
554 0x74, 0x06,
555 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
556 0xe8, 0x00, 0x00, 0x00, 0x00,
557 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
558 };
559 unsigned char *code = malloc(sizeof(temp));
560 unsigned int next_insn;
561 if (code) {
562 memcpy(code, temp, sizeof(temp));
563
564 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
565 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
566 next_insn = (unsigned int)(code + 0x14);
567 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
568 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
569 }
570 return code;
davem69775355a2001-06-05 23:54:00 +0000571#elif defined(USE_SPARC_ASM)
572
573#ifdef __sparc_v9__
574 static const unsigned int insn_template[] = {
575 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
576 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
577 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
578 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
579 0x8528b020, /* sllx %g2, 32, %g2 */
580 0xc2584002, /* ldx [%g1 + %g2], %g1 */
581 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
582 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
583 0xc6584002, /* ldx [%g1 + %g2], %g3 */
584 0x81c0c000, /* jmpl %g3, %g0 */
585 0x01000000 /* nop */
586 };
587#else
588 static const unsigned int insn_template[] = {
589 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
590 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
591 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
592 0x81c0c000, /* jmpl %g3, %g0 */
593 0x01000000 /* nop */
594 };
595#endif
596 unsigned int *code = malloc(sizeof(insn_template));
597 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
598 if (code) {
599 memcpy(code, insn_template, sizeof(insn_template));
600
601#ifdef __sparc_v9__
602 code[0] |= (glapi_addr >> (32 + 10));
603 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
davem694a497e62001-06-06 22:55:28 +0000604 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000605 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
606 code[3] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000607 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000608 code[6] |= ((functionOffset * 8) >> 10);
609 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000610 __glapi_sparc_icache_flush(&code[6]);
davem69775355a2001-06-05 23:54:00 +0000611#else
612 code[0] |= (glapi_addr >> 10);
613 code[1] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000614 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000615 code[2] |= (functionOffset * 4);
davem694a497e62001-06-06 22:55:28 +0000616 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000617#endif
618 }
619 return code;
Brian Paul959f8022000-03-19 01:10:11 +0000620#else
621 return NULL;
622#endif
623}
624
625
626
627/*
628 * Add a new extension function entrypoint.
629 * Return: GL_TRUE = success or GL_FALSE = failure
630 */
631GLboolean
632_glapi_add_entrypoint(const char *funcName, GLuint offset)
633{
Brian Paul959f8022000-03-19 01:10:11 +0000634 /* first check if the named function is already statically present */
635 {
636 GLint index = get_static_proc_offset(funcName);
637 if (index >= 0) {
Brian Paulb51b0a82001-03-07 05:06:11 +0000638 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
Brian Paul959f8022000-03-19 01:10:11 +0000639 }
640 }
641
642 {
643 /* make sure this offset/name pair is legal */
644 const char *name = _glapi_get_proc_name(offset);
645 if (name && strcmp(name, funcName) != 0)
646 return GL_FALSE; /* bad name! */
647 }
648
649 {
650 /* be sure index and name match known data */
651 GLuint i;
652 for (i = 0; i < NumExtEntryPoints; i++) {
653 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
654 /* function already registered with api */
655 if (ExtEntryTable[i].Offset == offset) {
656 return GL_TRUE; /* offsets match */
657 }
658 else {
659 return GL_FALSE; /* bad offset! */
660 }
661 }
662 }
663
Brian Paul2c3a6202000-05-24 17:53:30 +0000664 /* Make sure we don't try to add a new entrypoint after someone
665 * has already called _glapi_get_dispatch_table_size()! If that's
666 * happened the caller's information would become out of date.
667 */
668 if (GetSizeCalled)
669 return GL_FALSE;
670
Brian Paul959f8022000-03-19 01:10:11 +0000671 /* make sure we have space */
672 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS) {
673 return GL_FALSE;
674 }
675 else {
676 void *entrypoint = generate_entrypoint(offset);
677 if (!entrypoint)
678 return GL_FALSE;
679
Brian Paulfffb8092000-03-29 18:46:11 +0000680 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
Brian Paul959f8022000-03-19 01:10:11 +0000681 ExtEntryTable[NumExtEntryPoints].Offset = offset;
682 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
683 NumExtEntryPoints++;
684
685 if (offset > MaxDispatchOffset)
686 MaxDispatchOffset = offset;
687
688 return GL_TRUE; /* success */
689 }
690 }
691
692 /* should never get here, but play it safe */
693 return GL_FALSE;
694}
695
696
697
698#if 0000 /* prototype code for dynamic extension slot allocation */
699
700static int NextFreeOffset = 409; /*XXX*/
701#define MAX_DISPATCH_TABLE_SIZE 1000
702
703/*
704 * Dynamically allocate a dispatch slot for an extension entrypoint
705 * and generate the assembly language dispatch stub.
706 * Return the dispatch offset for the function or -1 if no room or error.
707 */
708GLint
709_glapi_add_entrypoint2(const char *funcName)
710{
711 int offset;
712
713 /* first see if extension func is already known */
714 offset = _glapi_get_proc_offset(funcName);
715 if (offset >= 0)
716 return offset;
717
718 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS
719 && NextFreeOffset < MAX_DISPATCH_TABLE_SIZE) {
720 void *entryPoint;
721 offset = NextFreeOffset;
722 entryPoint = generate_entrypoint(offset);
723 if (entryPoint) {
724 NextFreeOffset++;
Brian Paulfffb8092000-03-29 18:46:11 +0000725 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
Brian Paul959f8022000-03-19 01:10:11 +0000726 ExtEntryTable[NumExtEntryPoints].Offset = offset;
727 ExtEntryTable[NumExtEntryPoints].Address = entryPoint;
728 NumExtEntryPoints++;
729 return offset;
730 }
731 }
732 return -1;
733}
734
735#endif
736
737
738
739/*
740 * Return offset of entrypoint for named function within dispatch table.
741 */
742GLint
743_glapi_get_proc_offset(const char *funcName)
744{
745 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000746 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000747 for (i = 0; i < NumExtEntryPoints; i++) {
748 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
749 return ExtEntryTable[i].Offset;
750 }
751 }
752
753 /* search static functions */
754 return get_static_proc_offset(funcName);
755}
756
757
758
759/*
760 * Return entrypoint for named function.
761 */
762const GLvoid *
763_glapi_get_proc_address(const char *funcName)
764{
765 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000766 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000767 for (i = 0; i < NumExtEntryPoints; i++) {
768 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
769 return ExtEntryTable[i].Address;
770 }
771 }
772
773 /* search static functions */
774 return get_static_proc_address(funcName);
775}
776
777
778
779
780/*
781 * Return the name of the function at the given dispatch offset.
782 * This is only intended for debugging.
783 */
784const char *
785_glapi_get_proc_name(GLuint offset)
786{
787 const GLuint n = sizeof(static_functions) / sizeof(struct name_address_offset);
788 GLuint i;
789 for (i = 0; i < n; i++) {
790 if (static_functions[i].Offset == offset)
791 return static_functions[i].Name;
792 }
793
794 /* search added extension functions */
795 for (i = 0; i < NumExtEntryPoints; i++) {
796 if (ExtEntryTable[i].Offset == offset) {
797 return ExtEntryTable[i].Name;
798 }
799 }
800 return NULL;
801}
802
803
804
805/*
806 * Make sure there are no NULL pointers in the given dispatch table.
Brian Paul5104b4d2002-03-07 21:50:41 +0000807 * Intended for debugging purposes.
Brian Paul959f8022000-03-19 01:10:11 +0000808 */
809void
810_glapi_check_table(const struct _glapi_table *table)
811{
Brian Paul5104b4d2002-03-07 21:50:41 +0000812#ifdef DEBUG
Brian Paul959f8022000-03-19 01:10:11 +0000813 const GLuint entries = _glapi_get_dispatch_table_size();
814 const void **tab = (const void **) table;
815 GLuint i;
816 for (i = 1; i < entries; i++) {
817 assert(tab[i]);
818 }
819
Brian Paul959f8022000-03-19 01:10:11 +0000820 /* Do some spot checks to be sure that the dispatch table
821 * slots are assigned correctly.
822 */
823 {
824 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
825 char *BeginFunc = (char*) &table->Begin;
826 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
827 assert(BeginOffset == _gloffset_Begin);
828 assert(BeginOffset == offset);
829 }
830 {
831 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
832 char *viewportFunc = (char*) &table->Viewport;
833 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
834 assert(viewportOffset == _gloffset_Viewport);
835 assert(viewportOffset == offset);
836 }
837 {
838 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
839 char *VertexPointerFunc = (char*) &table->VertexPointer;
840 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
841 assert(VertexPointerOffset == _gloffset_VertexPointer);
842 assert(VertexPointerOffset == offset);
843 }
844 {
845 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
846 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
847 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
848 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
849 assert(ResetMinMaxOffset == offset);
850 }
851 {
852 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
853 char *blendColorFunc = (char*) &table->BlendColor;
854 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
855 assert(blendColorOffset == _gloffset_BlendColor);
856 assert(blendColorOffset == offset);
857 }
858 {
859 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
860 char *istextureFunc = (char*) &table->IsTextureEXT;
861 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
862 assert(istextureOffset == _gloffset_IsTextureEXT);
863 assert(istextureOffset == offset);
864 }
Brian Paula14cbff2000-10-27 18:31:21 +0000865 {
866 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
867 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
868 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
869 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
870 assert(secondaryColor3fOffset == offset);
871 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
872 }
Brian Paul91d6f122002-05-29 15:23:16 +0000873 {
874 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
875 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
876 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
877 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
878 assert(pointParameterivOffset == offset);
879 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
880 }
Brian Paul959f8022000-03-19 01:10:11 +0000881#endif
882}