Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included
14
 * in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
 * OTHER DEALINGS IN THE SOFTWARE.
23
 */
24
 
25
 
26
/*
27
 * This file manages the OpenGL API dispatch layer.
28
 * The dispatch table (struct _glapi_table) is basically just a list
29
 * of function pointers.
30
 * There are functions to set/get the current dispatch table for the
31
 * current thread and to manage registration/dispatch of dynamically
32
 * added extension functions.
33
 *
34
 * It's intended that this file and the other glapi*.[ch] files are
35
 * flexible enough to be reused in several places:  XFree86, DRI-
36
 * based libGL.so, and perhaps the SGI SI.
37
 *
38
 * NOTE: There are no dependencies on Mesa in this code.
39
 *
40
 * Versions (API changes):
41
 *   2000/02/23  - original version for Mesa 3.3 and XFree86 4.0
42
 *   2001/01/16  - added dispatch override feature for Mesa 3.5
43
 *   2002/06/28  - added _glapi_set_warning_func(), Mesa 4.1.
44
 *   2002/10/01  - _glapi_get_proc_address() will now generate new entrypoints
45
 *                 itself (using offset ~0).  _glapi_add_entrypoint() can be
46
 *                 called afterward and it'll fill in the correct dispatch
47
 *                 offset.  This allows DRI libGL to avoid probing for DRI
48
 *                 drivers!  No changes to the public glapi interface.
49
 */
50
 
51
#include "u_current.h"
52
#include "u_thread.h"
53
 
54
#ifndef MAPI_MODE_UTIL
55
 
56
#include "table.h"
57
#include "stub.h"
58
 
59
#else
60
 
61
extern void init_glapi_relocs_once(void);
62
extern void (*__glapi_noop_table[])(void);
63
 
64
#define table_noop_array __glapi_noop_table
65
#define stub_init_once() init_glapi_relocs_once()
66
 
67
#endif
68
 
69
/**
70
 * \name Current dispatch and current context control variables
71
 *
72
 * Depending on whether or not multithreading is support, and the type of
73
 * support available, several variables are used to store the current context
74
 * pointer and the current dispatch table pointer.  In the non-threaded case,
75
 * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this
76
 * purpose.
77
 *
78
 * In the "normal" threaded case, the variables \c _glapi_Dispatch and
79
 * \c _glapi_Context will be \c NULL if an application is detected as being
80
 * multithreaded.  Single-threaded applications will use \c _glapi_Dispatch
81
 * and \c _glapi_Context just like the case without any threading support.
82
 * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state
83
 * data \c _gl_DispatchTSD and \c ContextTSD are used.  Drivers and the
84
 * static dispatch functions access these variables via \c _glapi_get_dispatch
85
 * and \c _glapi_get_context.
86
 *
87
 * There is a race condition in setting \c _glapi_Dispatch to \c NULL.  It is
88
 * possible for the original thread to be setting it at the same instant a new
89
 * thread, perhaps running on a different processor, is clearing it.  Because
90
 * of that, \c ThreadSafe, which can only ever be changed to \c GL_TRUE, is
91
 * used to determine whether or not the application is multithreaded.
92
 *
93
 * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are
94
 * hardcoded to \c NULL.  Instead the TLS variables \c _glapi_tls_Dispatch and
95
 * \c _glapi_tls_Context are used.  Having \c _glapi_Dispatch and
96
 * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability
97
 * between TLS enabled loaders and non-TLS DRI drivers.
98
 */
99
/*@{*/
100
#if defined(GLX_USE_TLS)
101
 
102
__thread struct mapi_table *u_current_table
103
    __attribute__((tls_model("initial-exec")))
104
    = (struct mapi_table *) table_noop_array;
105
 
106
__thread void *u_current_user
107
    __attribute__((tls_model("initial-exec")));
108
 
109
#else
110
 
111
struct mapi_table *u_current_table =
112
   (struct mapi_table *) table_noop_array;
113
void *u_current_user;
114
 
115
#ifdef THREADS
116
struct u_tsd u_current_table_tsd;
117
static struct u_tsd u_current_user_tsd;
118
static int ThreadSafe;
119
#endif /* THREADS */
120
 
121
#endif /* defined(GLX_USE_TLS) */
122
/*@}*/
123
 
124
 
125
void
126
u_current_destroy(void)
127
{
128
#if defined(THREADS) && defined(_WIN32)
129
   u_tsd_destroy(&u_current_table_tsd);
130
   u_tsd_destroy(&u_current_user_tsd);
131
#endif
132
}
133
 
134
 
135
#if defined(THREADS) && !defined(GLX_USE_TLS)
136
 
137
static void
138
u_current_init_tsd(void)
139
{
140
   u_tsd_init(&u_current_table_tsd);
141
   u_tsd_init(&u_current_user_tsd);
142
}
143
 
144
/**
145
 * Mutex for multithread check.
146
 */
147
u_mutex_declare_static(ThreadCheckMutex);
148
 
149
/**
150
 * We should call this periodically from a function such as glXMakeCurrent
151
 * in order to test if multiple threads are being used.
152
 */
153
void
154
u_current_init(void)
155
{
156
   static unsigned long knownID;
157
   static int firstCall = 1;
158
 
159
   if (ThreadSafe)
160
      return;
161
 
162
   u_mutex_lock(ThreadCheckMutex);
163
   if (firstCall) {
164
      u_current_init_tsd();
165
 
166
      knownID = u_thread_self();
167
      firstCall = 0;
168
   }
169
   else if (knownID != u_thread_self()) {
170
      ThreadSafe = 1;
171
      u_current_set(NULL);
172
      u_current_set_user(NULL);
173
   }
174
   u_mutex_unlock(ThreadCheckMutex);
175
}
176
 
177
#else
178
 
179
void
180
u_current_init(void)
181
{
182
}
183
 
184
#endif
185
 
186
 
187
 
188
/**
189
 * Set the current context pointer for this thread.
190
 * The context pointer is an opaque type which should be cast to
191
 * void from the real context pointer type.
192
 */
193
void
194
u_current_set_user(const void *ptr)
195
{
196
   u_current_init();
197
 
198
#if defined(GLX_USE_TLS)
199
   u_current_user = (void *) ptr;
200
#elif defined(THREADS)
201
   u_tsd_set(&u_current_user_tsd, (void *) ptr);
202
   u_current_user = (ThreadSafe) ? NULL : (void *) ptr;
203
#else
204
   u_current_user = (void *) ptr;
205
#endif
206
}
207
 
208
/**
209
 * Get the current context pointer for this thread.
210
 * The context pointer is an opaque type which should be cast from
211
 * void to the real context pointer type.
212
 */
213
void *
214
u_current_get_user_internal(void)
215
{
216
#if defined(GLX_USE_TLS)
217
   return u_current_user;
218
#elif defined(THREADS)
219
   return (ThreadSafe)
220
      ? u_tsd_get(&u_current_user_tsd)
221
      : u_current_user;
222
#else
223
   return u_current_user;
224
#endif
225
}
226
 
227
/**
228
 * Set the global or per-thread dispatch table pointer.
229
 * If the dispatch parameter is NULL we'll plug in the no-op dispatch
230
 * table (__glapi_noop_table).
231
 */
232
void
233
u_current_set(const struct mapi_table *tbl)
234
{
235
   u_current_init();
236
 
237
   stub_init_once();
238
 
239
   if (!tbl)
240
      tbl = (const struct mapi_table *) table_noop_array;
241
 
242
#if defined(GLX_USE_TLS)
243
   u_current_table = (struct mapi_table *) tbl;
244
#elif defined(THREADS)
245
   u_tsd_set(&u_current_table_tsd, (void *) tbl);
246
   u_current_table = (ThreadSafe) ? NULL : (void *) tbl;
247
#else
248
   u_current_table = (struct mapi_table *) tbl;
249
#endif
250
}
251
 
252
/**
253
 * Return pointer to current dispatch table for calling thread.
254
 */
255
struct mapi_table *
256
u_current_get_internal(void)
257
{
258
#if defined(GLX_USE_TLS)
259
   return u_current_table;
260
#elif defined(THREADS)
261
   return (struct mapi_table *) ((ThreadSafe) ?
262
         u_tsd_get(&u_current_table_tsd) : (void *) u_current_table);
263
#else
264
   return u_current_table;
265
#endif
266
}