blob: 8649a5241da3d8fa1c2a319fca295dffa5d2064d [file] [log] [blame]
Brian Paul944ea202002-10-17 16:29:17 +00001/* $Id: glapi.c,v 1.66 2002/10/17 16:29:17 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 Paul54f3aab2002-10-02 01:51:44 +000046 * 2002/10/01 - _glapi_get_proc_address() will now generate new entrypoints
47 * itself (using offset ~0). _glapi_add_entrypoint() can be
48 * called afterward and it'll fill in the correct dispatch
49 * offset. This allows DRI libGL to avoid probing for DRI
50 * drivers! No changes to the public glapi interface.
Brian Paul7e1161b1999-11-25 18:17:04 +000051 */
52
53
54
Brian Paul3c27be32000-02-10 21:27:48 +000055#include "glheader.h"
Brian Paulfbd8f211999-11-11 01:22:25 +000056#include "glapi.h"
Brian Paul0c239fc1999-12-16 12:38:11 +000057#include "glapioffsets.h"
58#include "glapitable.h"
Brian Paul9f943992000-01-28 19:03:33 +000059#include "glthread.h"
Brian Paulbb72d321999-12-16 17:31:59 +000060
Brian Paul3c257e12001-03-28 17:19:58 +000061/***** BEGIN NO-OP DISPATCH *****/
62
63static GLboolean WarnFlag = GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000064static _glapi_warning_func warning_func;
Brian Paul3c257e12001-03-28 17:19:58 +000065
Brian Paul4e9676f2002-06-29 19:48:15 +000066
67/*
68 * Enable/disable printing of warning messages.
69 */
Brian Paul3c257e12001-03-28 17:19:58 +000070void
71_glapi_noop_enable_warnings(GLboolean enable)
72{
73 WarnFlag = enable;
74}
75
Brian Paul4e9676f2002-06-29 19:48:15 +000076/*
77 * Register a callback function for reporting errors.
78 */
79void
80_glapi_set_warning_func( _glapi_warning_func func )
81{
82 warning_func = func;
83}
84
Brian Paul3c257e12001-03-28 17:19:58 +000085static GLboolean
86warn(void)
87{
Brian Paul4e9676f2002-06-29 19:48:15 +000088 if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
89 && warning_func) {
Brian Paul3c257e12001-03-28 17:19:58 +000090 return GL_TRUE;
Brian Paul4e9676f2002-06-29 19:48:15 +000091 }
92 else {
Brian Paul3c257e12001-03-28 17:19:58 +000093 return GL_FALSE;
Brian Paul4e9676f2002-06-29 19:48:15 +000094 }
Brian Paul3c257e12001-03-28 17:19:58 +000095}
96
97
98#define KEYWORD1 static
99#define KEYWORD2
100#define NAME(func) NoOp##func
101
Brian Paul4e9676f2002-06-29 19:48:15 +0000102#define F NULL
Brian Paul3c257e12001-03-28 17:19:58 +0000103
Brian Paul4e9676f2002-06-29 19:48:15 +0000104#define DISPATCH(func, args, msg) \
105 if (warn()) { \
106 warning_func(NULL, "GL User Error: called without context:"); \
107 warning_func msg; \
Brian Paul3c257e12001-03-28 17:19:58 +0000108 }
109
Brian Paul4e9676f2002-06-29 19:48:15 +0000110#define RETURN_DISPATCH(func, args, msg) \
111 if (warn()) { \
112 warning_func(NULL, "GL User Error: called without context:"); \
113 warning_func msg; \
114 } \
Brian Paul3c257e12001-03-28 17:19:58 +0000115 return 0
116
117#define DISPATCH_TABLE_NAME __glapi_noop_table
118#define UNUSED_TABLE_NAME __usused_noop_functions
119
120#define TABLE_ENTRY(name) (void *) NoOp##name
121
122static int NoOpUnused(void)
123{
124 if (warn()) {
Brian Paul4e9676f2002-06-29 19:48:15 +0000125 warning_func(NULL, "GL User Error: calling extension function without a current context\n");
Brian Paul3c257e12001-03-28 17:19:58 +0000126 }
127 return 0;
128}
129
130#include "glapitemp.h"
131
132/***** END NO-OP DISPATCH *****/
133
134
135
136/***** BEGIN THREAD-SAFE DISPATCH *****/
137/* if we support thread-safety, build a special dispatch table for use
138 * in thread-safety mode (ThreadSafe == GL_TRUE). Each entry in the
139 * dispatch table will call _glthread_GetTSD() to get the actual dispatch
140 * table bound to the current thread, then jump through that table.
141 */
142
143#if defined(THREADS)
144
145static GLboolean ThreadSafe = GL_FALSE; /* In thread-safe mode? */
146static _glthread_TSD DispatchTSD; /* Per-thread dispatch pointer */
147static _glthread_TSD RealDispatchTSD; /* only when using override */
148static _glthread_TSD ContextTSD; /* Per-thread context pointer */
149
150
151#define KEYWORD1 static
152#define KEYWORD2 GLAPIENTRY
153#define NAME(func) _ts_##func
154
155#define DISPATCH(FUNC, ARGS, MESSAGE) \
156 struct _glapi_table *dispatch; \
157 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
158 if (!dispatch) \
159 dispatch = (struct _glapi_table *) __glapi_noop_table; \
160 (dispatch->FUNC) ARGS
161
162#define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \
163 struct _glapi_table *dispatch; \
164 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
165 if (!dispatch) \
166 dispatch = (struct _glapi_table *) __glapi_noop_table; \
167 return (dispatch->FUNC) ARGS
168
169#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
170#define UNUSED_TABLE_NAME __usused_threadsafe_functions
171
172#define TABLE_ENTRY(name) (void *) _ts_##name
173
174static int _ts_Unused(void)
175{
176 return 0;
177}
178
179#include "glapitemp.h"
180
181#endif
182
183/***** END THREAD-SAFE DISPATCH *****/
184
185
186
Brian Paul8ceb5c32000-02-24 22:14:04 +0000187struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000188struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul0f710251999-12-15 15:02:30 +0000189
Brian Paul8f91fb61999-12-17 14:51:28 +0000190/* Used when thread safety disabled */
Brian Paulf9b97d92000-01-28 20:17:42 +0000191void *_glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000192
Brian Paul0f710251999-12-15 15:02:30 +0000193
Brian Paulab0c8862001-01-23 23:35:47 +0000194static GLboolean DispatchOverride = GL_FALSE;
195
196
Brian Paul54f3aab2002-10-02 01:51:44 +0000197
Brian Paul3c257e12001-03-28 17:19:58 +0000198/* strdup() is actually not a standard ANSI C or POSIX routine.
199 * Irix will not define it if ANSI mode is in effect.
200 */
201static char *
202str_dup(const char *str)
Randy Frankd7361e12000-03-27 21:13:58 +0000203{
Brian Paulfffb8092000-03-29 18:46:11 +0000204 char *copy;
205 copy = (char*) malloc(strlen(str) + 1);
206 if (!copy)
207 return NULL;
208 strcpy(copy, str);
209 return copy;
Randy Frankd7361e12000-03-27 21:13:58 +0000210}
211
Brian Paul7fb54ae1999-11-19 22:33:50 +0000212
Brian Paulbb72d321999-12-16 17:31:59 +0000213
214/*
215 * We should call this periodically from a function such as glXMakeCurrent
Brian Paul5104b4d2002-03-07 21:50:41 +0000216 * in order to test if multiple threads are being used.
Brian Paulbb72d321999-12-16 17:31:59 +0000217 */
218void
219_glapi_check_multithread(void)
220{
221#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000222 if (!ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000223 static unsigned long knownID;
224 static GLboolean firstCall = GL_TRUE;
225 if (firstCall) {
226 knownID = _glthread_GetID();
227 firstCall = GL_FALSE;
228 }
229 else if (knownID != _glthread_GetID()) {
Brian Paul26e14d22000-01-05 04:36:17 +0000230 ThreadSafe = GL_TRUE;
Brian Paulbb72d321999-12-16 17:31:59 +0000231 }
232 }
Brian Paul26e14d22000-01-05 04:36:17 +0000233 if (ThreadSafe) {
Brian Paulbb72d321999-12-16 17:31:59 +0000234 /* make sure that this thread's dispatch pointer isn't null */
235 if (!_glapi_get_dispatch()) {
236 _glapi_set_dispatch(NULL);
237 }
238 }
239#endif
240}
241
242
243
244/*
Brian Paul8f91fb61999-12-17 14:51:28 +0000245 * Set the current context pointer for this thread.
246 * The context pointer is an opaque type which should be cast to
247 * void from the real context pointer type.
248 */
249void
Brian Paulf9b97d92000-01-28 20:17:42 +0000250_glapi_set_context(void *context)
Brian Paul8f91fb61999-12-17 14:51:28 +0000251{
252#if defined(THREADS)
Brian Paul3c27be32000-02-10 21:27:48 +0000253 _glthread_SetTSD(&ContextTSD, context);
Brian Paul26e14d22000-01-05 04:36:17 +0000254 if (ThreadSafe)
Brian Paulf9b97d92000-01-28 20:17:42 +0000255 _glapi_Context = NULL;
Brian Paul8f91fb61999-12-17 14:51:28 +0000256 else
Brian Paulf9b97d92000-01-28 20:17:42 +0000257 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000258#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000259 _glapi_Context = context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000260#endif
261}
262
263
264
265/*
266 * Get the current context pointer for this thread.
267 * The context pointer is an opaque type which should be cast from
268 * void to the real context pointer type.
269 */
270void *
Brian Paulf9b97d92000-01-28 20:17:42 +0000271_glapi_get_context(void)
Brian Paul8f91fb61999-12-17 14:51:28 +0000272{
273#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000274 if (ThreadSafe) {
Brian Paul8f91fb61999-12-17 14:51:28 +0000275 return _glthread_GetTSD(&ContextTSD);
276 }
277 else {
Brian Paulf9b97d92000-01-28 20:17:42 +0000278 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000279 }
280#else
Brian Paulf9b97d92000-01-28 20:17:42 +0000281 return _glapi_Context;
Brian Paul8f91fb61999-12-17 14:51:28 +0000282#endif
283}
284
285
286
287/*
Brian Paul7fb54ae1999-11-19 22:33:50 +0000288 * Set the global or per-thread dispatch table pointer.
289 */
290void
291_glapi_set_dispatch(struct _glapi_table *dispatch)
292{
293 if (!dispatch) {
294 /* use the no-op functions */
Brian Paul8ceb5c32000-02-24 22:14:04 +0000295 dispatch = (struct _glapi_table *) __glapi_noop_table;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000296 }
297#ifdef DEBUG
298 else {
299 _glapi_check_table(dispatch);
300 }
301#endif
302
303#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000304 if (DispatchOverride) {
305 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000306 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000307 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000308 else
Brian Paulab0c8862001-01-23 23:35:47 +0000309 _glapi_RealDispatch = dispatch;
Brian Paul3b18a362000-09-26 15:27:20 +0000310 }
311 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000312 /* normal operation */
Brian Paul3b18a362000-09-26 15:27:20 +0000313 _glthread_SetTSD(&DispatchTSD, (void *) dispatch);
Brian Paul3a71d052000-09-05 20:17:37 +0000314 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000315 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paul3a71d052000-09-05 20:17:37 +0000316 else
317 _glapi_Dispatch = dispatch;
318 }
Brian Paul3a71d052000-09-05 20:17:37 +0000319#else /*THREADS*/
Brian Paulab0c8862001-01-23 23:35:47 +0000320 if (DispatchOverride) {
321 _glapi_RealDispatch = dispatch;
322 }
323 else {
324 _glapi_Dispatch = dispatch;
325 }
Brian Paul3a71d052000-09-05 20:17:37 +0000326#endif /*THREADS*/
Brian Paul7fb54ae1999-11-19 22:33:50 +0000327}
328
329
Brian Paulbb72d321999-12-16 17:31:59 +0000330
Brian Paul7fb54ae1999-11-19 22:33:50 +0000331/*
Brian Paulbb72d321999-12-16 17:31:59 +0000332 * Return pointer to current dispatch table for calling thread.
Brian Paul7fb54ae1999-11-19 22:33:50 +0000333 */
334struct _glapi_table *
335_glapi_get_dispatch(void)
336{
337#if defined(THREADS)
Brian Paul26e14d22000-01-05 04:36:17 +0000338 if (ThreadSafe) {
Brian Paulab0c8862001-01-23 23:35:47 +0000339 if (DispatchOverride) {
340 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
341 }
342 else {
343 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
344 }
Brian Paulbb72d321999-12-16 17:31:59 +0000345 }
Brian Paul590d3471999-12-17 12:20:23 +0000346 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000347 if (DispatchOverride) {
348 assert(_glapi_RealDispatch);
349 return _glapi_RealDispatch;
350 }
351 else {
352 assert(_glapi_Dispatch);
353 return _glapi_Dispatch;
354 }
Brian Paul590d3471999-12-17 12:20:23 +0000355 }
Brian Paul7fb54ae1999-11-19 22:33:50 +0000356#else
Brian Paulc2319b42000-01-17 19:28:31 +0000357 return _glapi_Dispatch;
Brian Paul7fb54ae1999-11-19 22:33:50 +0000358#endif
359}
360
361
Brian Paulab0c8862001-01-23 23:35:47 +0000362/*
363 * Notes on dispatch overrride:
364 *
365 * Dispatch override allows an external agent to hook into the GL dispatch
366 * mechanism before execution goes into the core rendering library. For
367 * example, a trace mechanism would insert itself as an overrider, print
368 * logging info for each GL function, then dispatch to the real GL function.
369 *
370 * libGLS (GL Stream library) is another agent that might use override.
371 *
372 * We don't allow more than one layer of overriding at this time.
373 * In the future we may allow nested/layered override. In that case
374 * _glapi_begin_dispatch_override() will return an override layer,
375 * _glapi_end_dispatch_override(layer) will remove an override layer
376 * and _glapi_get_override_dispatch(layer) will return the dispatch
377 * table for a given override layer. layer = 0 will be the "real"
378 * dispatch table.
379 */
380
381/*
382 * Return: dispatch override layer number.
383 */
384int
385_glapi_begin_dispatch_override(struct _glapi_table *override)
Brian Paul3a71d052000-09-05 20:17:37 +0000386{
Brian Paulab0c8862001-01-23 23:35:47 +0000387 struct _glapi_table *real = _glapi_get_dispatch();
388
389 assert(!DispatchOverride); /* can't nest at this time */
390 DispatchOverride = GL_TRUE;
391
392 _glapi_set_dispatch(real);
Brian Paul3a71d052000-09-05 20:17:37 +0000393
394#if defined(THREADS)
Brian Paulab0c8862001-01-23 23:35:47 +0000395 _glthread_SetTSD(&DispatchTSD, (void *) override);
396 if (ThreadSafe)
Brian Paul3c257e12001-03-28 17:19:58 +0000397 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
Brian Paulab0c8862001-01-23 23:35:47 +0000398 else
399 _glapi_Dispatch = override;
400#else
401 _glapi_Dispatch = override;
402#endif
403 return 1;
404}
405
406
407void
408_glapi_end_dispatch_override(int layer)
409{
410 struct _glapi_table *real = _glapi_get_dispatch();
411 (void) layer;
412 DispatchOverride = GL_FALSE;
413 _glapi_set_dispatch(real);
414 /* the rest of this isn't needed, just play it safe */
415#if defined(THREADS)
416 _glthread_SetTSD(&RealDispatchTSD, NULL);
417#endif
418 _glapi_RealDispatch = NULL;
419}
420
421
422struct _glapi_table *
423_glapi_get_override_dispatch(int layer)
424{
425 if (layer == 0) {
426 return _glapi_get_dispatch();
Brian Paul3a71d052000-09-05 20:17:37 +0000427 }
428 else {
Brian Paulab0c8862001-01-23 23:35:47 +0000429 if (DispatchOverride) {
430#if defined(THREADS)
431 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
Brian Paul3a71d052000-09-05 20:17:37 +0000432#else
Brian Paulab0c8862001-01-23 23:35:47 +0000433 return _glapi_Dispatch;
Brian Paul3a71d052000-09-05 20:17:37 +0000434#endif
Brian Paulab0c8862001-01-23 23:35:47 +0000435 }
436 else {
437 return NULL;
438 }
439 }
Brian Paul3a71d052000-09-05 20:17:37 +0000440}
Brian Paulab0c8862001-01-23 23:35:47 +0000441
Brian Paul3a71d052000-09-05 20:17:37 +0000442
Brian Paul959f8022000-03-19 01:10:11 +0000443struct name_address_offset {
444 const char *Name;
445 GLvoid *Address;
446 GLuint Offset;
447};
448
Brian Paul0c239fc1999-12-16 12:38:11 +0000449
Brian Paul54f3aab2002-10-02 01:51:44 +0000450/* The code in this file is auto-generated with Python */
Brian Paulb5fd8862001-11-18 22:48:11 +0000451#include "glprocs.h"
Brian Paul7fb54ae1999-11-19 22:33:50 +0000452
Brian Paul959f8022000-03-19 01:10:11 +0000453
454
455/*
456 * Return dispatch table offset of the named static (built-in) function.
457 * Return -1 if function not found.
458 */
459static GLint
460get_static_proc_offset(const char *funcName)
461{
462 GLuint i;
463 for (i = 0; static_functions[i].Name; i++) {
464 if (strcmp(static_functions[i].Name, funcName) == 0) {
Brian Paul94666c42001-09-14 02:48:53 +0000465 return static_functions[i].Offset;
Brian Paul959f8022000-03-19 01:10:11 +0000466 }
467 }
468 return -1;
469}
470
471
472/*
473 * Return dispatch function address the named static (built-in) function.
474 * Return NULL if function not found.
475 */
476static GLvoid *
477get_static_proc_address(const char *funcName)
478{
Brian Paul9c7ca852000-10-19 20:13:12 +0000479 GLint i;
480 for (i = 0; static_functions[i].Name; i++) {
481 if (strcmp(static_functions[i].Name, funcName) == 0) {
482 return static_functions[i].Address;
483 }
484 }
485 return NULL;
Brian Paul959f8022000-03-19 01:10:11 +0000486}
487
488
489
490/**********************************************************************
491 * Extension function management.
492 */
493
Brian Paul54f3aab2002-10-02 01:51:44 +0000494/*
495 * Number of extension functions which we can dynamically add at runtime.
496 */
497#define MAX_EXTENSION_FUNCS 300
Brian Paul959f8022000-03-19 01:10:11 +0000498
Brian Paul54f3aab2002-10-02 01:51:44 +0000499
500/*
501 * The disptach table size (number of entries) is the sizeof the
502 * _glapi_table struct plus the number of dynamic entries we can add.
503 * The extra slots can be filled in by DRI drivers that register new extension
504 * functions.
505 */
506#define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
507
Brian Paul959f8022000-03-19 01:10:11 +0000508
509static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
510static GLuint NumExtEntryPoints = 0;
511
davem694a497e62001-06-06 22:55:28 +0000512#ifdef USE_SPARC_ASM
513extern void __glapi_sparc_icache_flush(unsigned int *);
514#endif
Brian Paul959f8022000-03-19 01:10:11 +0000515
516/*
517 * Generate a dispatch function (entrypoint) which jumps through
518 * the given slot number (offset) in the current dispatch table.
519 * We need assembly language in order to accomplish this.
520 */
521static void *
522generate_entrypoint(GLuint functionOffset)
523{
524#if defined(USE_X86_ASM)
525 /*
526 * This x86 code contributed by Josh Vanderhoof.
527 *
528 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
529 * 00 01 02 03 04
530 * 5: 85 c0 testl %eax,%eax
531 * 05 06
532 * 7: 74 06 je f <entrypoint+0xf>
533 * 07 08
534 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
535 * 09 0a 0b 0c 0d 0e
536 * f: e8 fc ff ff ff call __glapi_get_dispatch
537 * 0f 10 11 12 13
538 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
539 * 14 15 16 17 18 19
540 */
Brian Paul54f3aab2002-10-02 01:51:44 +0000541 static const unsigned char insn_template[] = {
Brian Paul959f8022000-03-19 01:10:11 +0000542 0xa1, 0x00, 0x00, 0x00, 0x00,
543 0x85, 0xc0,
544 0x74, 0x06,
545 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
546 0xe8, 0x00, 0x00, 0x00, 0x00,
547 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
548 };
Brian Paul54f3aab2002-10-02 01:51:44 +0000549 unsigned char *code = malloc(sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000550 unsigned int next_insn;
551 if (code) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000552 memcpy(code, insn_template, sizeof(insn_template));
Brian Paul959f8022000-03-19 01:10:11 +0000553
554 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
555 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
556 next_insn = (unsigned int)(code + 0x14);
557 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
558 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
559 }
560 return code;
davem69775355a2001-06-05 23:54:00 +0000561#elif defined(USE_SPARC_ASM)
562
563#ifdef __sparc_v9__
564 static const unsigned int insn_template[] = {
565 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
566 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
567 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
568 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
569 0x8528b020, /* sllx %g2, 32, %g2 */
570 0xc2584002, /* ldx [%g1 + %g2], %g1 */
571 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
572 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
573 0xc6584002, /* ldx [%g1 + %g2], %g3 */
574 0x81c0c000, /* jmpl %g3, %g0 */
575 0x01000000 /* nop */
576 };
577#else
578 static const unsigned int insn_template[] = {
579 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
580 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
581 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
582 0x81c0c000, /* jmpl %g3, %g0 */
583 0x01000000 /* nop */
584 };
585#endif
586 unsigned int *code = malloc(sizeof(insn_template));
587 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
588 if (code) {
589 memcpy(code, insn_template, sizeof(insn_template));
590
591#ifdef __sparc_v9__
592 code[0] |= (glapi_addr >> (32 + 10));
593 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
davem694a497e62001-06-06 22:55:28 +0000594 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000595 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
596 code[3] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000597 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000598 code[6] |= ((functionOffset * 8) >> 10);
599 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000600 __glapi_sparc_icache_flush(&code[6]);
davem69775355a2001-06-05 23:54:00 +0000601#else
602 code[0] |= (glapi_addr >> 10);
603 code[1] |= (glapi_addr & ((1 << 10) - 1));
davem694a497e62001-06-06 22:55:28 +0000604 __glapi_sparc_icache_flush(&code[0]);
davem69775355a2001-06-05 23:54:00 +0000605 code[2] |= (functionOffset * 4);
davem694a497e62001-06-06 22:55:28 +0000606 __glapi_sparc_icache_flush(&code[2]);
davem69775355a2001-06-05 23:54:00 +0000607#endif
608 }
609 return code;
Brian Paul959f8022000-03-19 01:10:11 +0000610#else
611 return NULL;
Brian Paul54f3aab2002-10-02 01:51:44 +0000612#endif /* USE_*_ASM */
Brian Paul959f8022000-03-19 01:10:11 +0000613}
614
615
Brian Paul54f3aab2002-10-02 01:51:44 +0000616/*
617 * This function inserts a new dispatch offset into the assembly language
618 * stub that was generated with the preceeding function.
619 */
620static void
621fill_in_entrypoint_offset(void *entrypoint, GLuint offset)
622{
623#if defined(USE_X86_ASM)
624
625 unsigned char *code = (unsigned char *) entrypoint;
626 *(unsigned int *)(code + 0x0b) = offset * 4;
627 *(unsigned int *)(code + 0x16) = offset * 4;
628
629#elif defined(USE_SPARC_ASM)
630
631 /* XXX this hasn't been tested! */
632 unsigned int *code = (unsigned int *) entrypoint;
633#ifdef __sparc_v9__
634 code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
635 code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
636 code[6] |= ((offset * 8) >> 10);
637 code[7] |= ((offset * 8) & ((1 << 10) - 1));
638 __glapi_sparc_icache_flush(&code[6]);
639#else /* __sparc_v9__ */
640 code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
Brian Paul944ea202002-10-17 16:29:17 +0000641 code[2] |= (offset * 4);
Brian Paul54f3aab2002-10-02 01:51:44 +0000642 __glapi_sparc_icache_flush(&code[2]);
643#endif /* __sparc_v9__ */
644
645#endif /* USE_*_ASM */
646}
647
Brian Paul959f8022000-03-19 01:10:11 +0000648
649/*
650 * Add a new extension function entrypoint.
651 * Return: GL_TRUE = success or GL_FALSE = failure
652 */
653GLboolean
654_glapi_add_entrypoint(const char *funcName, GLuint offset)
655{
Brian Paul8ad10762002-10-11 17:41:03 +0000656 /* trivial rejection test */
657 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
658 return GL_FALSE;
659
Brian Paul959f8022000-03-19 01:10:11 +0000660 /* first check if the named function is already statically present */
661 {
662 GLint index = get_static_proc_offset(funcName);
663 if (index >= 0) {
Brian Paulb51b0a82001-03-07 05:06:11 +0000664 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
Brian Paul959f8022000-03-19 01:10:11 +0000665 }
666 }
667
Brian Paul54f3aab2002-10-02 01:51:44 +0000668 /* See if this function has already been dynamically added */
Brian Paul959f8022000-03-19 01:10:11 +0000669 {
Brian Paul959f8022000-03-19 01:10:11 +0000670 GLuint i;
671 for (i = 0; i < NumExtEntryPoints; i++) {
672 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
Brian Paul54f3aab2002-10-02 01:51:44 +0000673 /* function already registered */
Brian Paul959f8022000-03-19 01:10:11 +0000674 if (ExtEntryTable[i].Offset == offset) {
675 return GL_TRUE; /* offsets match */
676 }
Brian Paul54f3aab2002-10-02 01:51:44 +0000677 else if (ExtEntryTable[i].Offset == ~0
678 && offset < DISPATCH_TABLE_SIZE) {
679 /* need to patch-up the dispatch code */
680 if (offset != ~0) {
681 fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
682 ExtEntryTable[i].Offset = offset;
683 }
684 return GL_TRUE;
685 }
Brian Paul959f8022000-03-19 01:10:11 +0000686 else {
687 return GL_FALSE; /* bad offset! */
688 }
689 }
690 }
Brian Paul959f8022000-03-19 01:10:11 +0000691 }
692
Brian Paul8ad10762002-10-11 17:41:03 +0000693 /* This is a new function, try to add it. */
694 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
695 offset >= DISPATCH_TABLE_SIZE) {
696 /* No space left */
697 return GL_FALSE;
698 }
699 else {
700 void *entrypoint = generate_entrypoint(offset);
701 if (!entrypoint)
702 return GL_FALSE; /* couldn't generate assembly */
703
704 /* OK! */
705 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
706 ExtEntryTable[NumExtEntryPoints].Offset = offset;
707 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
708 NumExtEntryPoints++;
709
710 return GL_TRUE; /* success */
711 }
712
713 /* should never get here, silence compiler warnings */
Brian Paul959f8022000-03-19 01:10:11 +0000714 return GL_FALSE;
715}
716
717
Brian Paul959f8022000-03-19 01:10:11 +0000718/*
719 * Return offset of entrypoint for named function within dispatch table.
720 */
721GLint
722_glapi_get_proc_offset(const char *funcName)
723{
724 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000725 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000726 for (i = 0; i < NumExtEntryPoints; i++) {
727 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
728 return ExtEntryTable[i].Offset;
729 }
730 }
731
732 /* search static functions */
733 return get_static_proc_offset(funcName);
734}
735
736
737
738/*
739 * Return entrypoint for named function.
740 */
741const GLvoid *
742_glapi_get_proc_address(const char *funcName)
743{
744 /* search extension functions first */
Brian Paulb51b0a82001-03-07 05:06:11 +0000745 GLuint i;
Brian Paul959f8022000-03-19 01:10:11 +0000746 for (i = 0; i < NumExtEntryPoints; i++) {
747 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
748 return ExtEntryTable[i].Address;
749 }
750 }
751
752 /* search static functions */
Brian Paul54f3aab2002-10-02 01:51:44 +0000753 {
754 const GLvoid *func = get_static_proc_address(funcName);
755 if (func)
756 return func;
757 }
Brian Paul959f8022000-03-19 01:10:11 +0000758
Brian Paul54f3aab2002-10-02 01:51:44 +0000759 /* generate new entrypoint - use a temporary dispatch offset of
760 * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
761 * we'll put in the proper offset. If that never happens, and the
762 * user calls this function, he'll segfault. That's what you get
763 * when you try calling a GL function that doesn't really exist.
764 */
765 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
766 GLvoid *entrypoint = generate_entrypoint(~0);
767 if (!entrypoint)
768 return GL_FALSE;
769
770 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
771 ExtEntryTable[NumExtEntryPoints].Offset = ~0;
772 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
773 NumExtEntryPoints++;
774
775 return entrypoint;
776 }
777 else {
778 /* no space for new functions! */
779 return NULL;
780 }
781}
Brian Paul959f8022000-03-19 01:10:11 +0000782
783
784
785/*
786 * Return the name of the function at the given dispatch offset.
787 * This is only intended for debugging.
788 */
789const char *
790_glapi_get_proc_name(GLuint offset)
791{
792 const GLuint n = sizeof(static_functions) / sizeof(struct name_address_offset);
793 GLuint i;
Brian Paul54f3aab2002-10-02 01:51:44 +0000794
795 /* search built-in functions */
Brian Paul959f8022000-03-19 01:10:11 +0000796 for (i = 0; i < n; i++) {
797 if (static_functions[i].Offset == offset)
798 return static_functions[i].Name;
799 }
800
801 /* search added extension functions */
802 for (i = 0; i < NumExtEntryPoints; i++) {
803 if (ExtEntryTable[i].Offset == offset) {
804 return ExtEntryTable[i].Name;
805 }
806 }
807 return NULL;
808}
809
810
811
812/*
Brian Paul54f3aab2002-10-02 01:51:44 +0000813 * Return size of dispatch table struct as number of functions (or
814 * slots).
815 */
816GLuint
817_glapi_get_dispatch_table_size(void)
818{
819 return DISPATCH_TABLE_SIZE;
820}
821
822
823
824/*
825 * Get API dispatcher version string.
826 */
827const char *
828_glapi_get_version(void)
829{
830 return "20021001"; /* YYYYMMDD */
831}
832
833
834
835/*
Brian Paul959f8022000-03-19 01:10:11 +0000836 * Make sure there are no NULL pointers in the given dispatch table.
Brian Paul5104b4d2002-03-07 21:50:41 +0000837 * Intended for debugging purposes.
Brian Paul959f8022000-03-19 01:10:11 +0000838 */
839void
840_glapi_check_table(const struct _glapi_table *table)
841{
Brian Paul5104b4d2002-03-07 21:50:41 +0000842#ifdef DEBUG
Brian Paul959f8022000-03-19 01:10:11 +0000843 const GLuint entries = _glapi_get_dispatch_table_size();
844 const void **tab = (const void **) table;
845 GLuint i;
846 for (i = 1; i < entries; i++) {
847 assert(tab[i]);
848 }
849
Brian Paul959f8022000-03-19 01:10:11 +0000850 /* Do some spot checks to be sure that the dispatch table
851 * slots are assigned correctly.
852 */
853 {
854 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
855 char *BeginFunc = (char*) &table->Begin;
856 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
857 assert(BeginOffset == _gloffset_Begin);
858 assert(BeginOffset == offset);
859 }
860 {
861 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
862 char *viewportFunc = (char*) &table->Viewport;
863 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
864 assert(viewportOffset == _gloffset_Viewport);
865 assert(viewportOffset == offset);
866 }
867 {
868 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
869 char *VertexPointerFunc = (char*) &table->VertexPointer;
870 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
871 assert(VertexPointerOffset == _gloffset_VertexPointer);
872 assert(VertexPointerOffset == offset);
873 }
874 {
875 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
876 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
877 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
878 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
879 assert(ResetMinMaxOffset == offset);
880 }
881 {
882 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
883 char *blendColorFunc = (char*) &table->BlendColor;
884 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
885 assert(blendColorOffset == _gloffset_BlendColor);
886 assert(blendColorOffset == offset);
887 }
888 {
889 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
890 char *istextureFunc = (char*) &table->IsTextureEXT;
891 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
892 assert(istextureOffset == _gloffset_IsTextureEXT);
893 assert(istextureOffset == offset);
894 }
Brian Paula14cbff2000-10-27 18:31:21 +0000895 {
896 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
897 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
898 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
899 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
900 assert(secondaryColor3fOffset == offset);
901 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
902 }
Brian Paul91d6f122002-05-29 15:23:16 +0000903 {
904 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
905 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
906 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
907 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
908 assert(pointParameterivOffset == offset);
909 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
910 }
Brian Paul54f3aab2002-10-02 01:51:44 +0000911 {
912 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
913 char *setFenceFunc = (char*) &table->SetFenceNV;
914 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
915 assert(setFenceOffset == _gloffset_SetFenceNV);
916 assert(setFenceOffset == offset);
917 assert(_glapi_get_proc_address("glSetFenceNV") == (void *) &glSetFenceNV);
918 }
Brian Paul959f8022000-03-19 01:10:11 +0000919#endif
920}