egl: Make display and surface hash tables local.
[mesa.git] / src / egl / main / egldisplay.c
1 /**
2 * Functions related to EGLDisplay.
3 */
4
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include "eglcontext.h"
9 #include "eglsurface.h"
10 #include "egldisplay.h"
11 #include "egldriver.h"
12 #include "eglglobals.h"
13 #include "eglhash.h"
14 #include "eglstring.h"
15 #include "eglmutex.h"
16
17
18 static _EGL_DECLARE_MUTEX(_eglDisplayInitMutex);
19 static _EGLHashtable *_eglDisplayHash;
20 /* TODO surface hash table should be per-display */
21 static _EGLHashtable *_eglSurfaceHash;
22
23
24 /**
25 * Finish display management.
26 */
27 static void
28 _eglFiniDisplay(void)
29 {
30 _eglLockMutex(&_eglDisplayInitMutex);
31 if (_eglDisplayHash) {
32 /* XXX TODO walk over table entries, deleting each */
33 _eglDeleteHashTable(_eglDisplayHash);
34 _eglDisplayHash = NULL;
35 _eglDeleteHashTable(_eglSurfaceHash);
36 _eglSurfaceHash = NULL;
37 }
38 _eglUnlockMutex(&_eglDisplayInitMutex);
39 }
40
41
42 /* This can be avoided if hash table can be statically initialized */
43 static INLINE void
44 _eglInitDisplay(void)
45 {
46 if (!_eglDisplayHash) {
47 _eglLockMutex(&_eglDisplayInitMutex);
48
49 /* check again after acquiring lock */
50 if (!_eglDisplayHash) {
51 _eglDisplayHash = _eglNewHashTable();
52 _eglSurfaceHash = _eglNewHashTable();
53
54 (void) _eglFiniDisplay;
55 }
56
57 _eglUnlockMutex(&_eglDisplayInitMutex);
58 }
59 }
60
61
62 /**
63 * Allocate a new _EGLDisplay object for the given nativeDisplay handle.
64 * We'll also try to determine the device driver name at this time.
65 *
66 * Note that nativeDisplay may be an X Display ptr, or a string.
67 */
68 _EGLDisplay *
69 _eglNewDisplay(NativeDisplayType nativeDisplay)
70 {
71 _EGLDisplay *dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
72 if (dpy) {
73 dpy->NativeDisplay = nativeDisplay;
74 #if defined(_EGL_PLATFORM_X)
75 dpy->Xdpy = (Display *) nativeDisplay;
76 #endif
77
78 _eglInitDisplay();
79 dpy->SurfaceHash = _eglSurfaceHash;
80
81 dpy->DriverName = _eglChooseDriver(dpy);
82 if (!dpy->DriverName) {
83 free(dpy);
84 return NULL;
85 }
86 }
87 return dpy;
88 }
89
90
91 /**
92 * Link a display to itself and return the handle of the link.
93 * The handle can be passed to client directly.
94 */
95 EGLDisplay
96 _eglLinkDisplay(_EGLDisplay *dpy)
97 {
98 EGLuint key;
99
100 _eglInitDisplay();
101
102 key = _eglHashGenKey(_eglDisplayHash);
103 assert(key);
104 /* "link" the display to the hash table */
105 _eglHashInsert(_eglDisplayHash, key, dpy);
106 dpy->Handle = (EGLDisplay) _eglUIntToPointer(key);
107
108 return dpy->Handle;
109 }
110
111
112 /**
113 * Unlink a linked display from itself.
114 * Accessing an unlinked display should generate EGL_BAD_DISPLAY error.
115 */
116 void
117 _eglUnlinkDisplay(_EGLDisplay *dpy)
118 {
119 EGLuint key = _eglPointerToUInt((void *) dpy->Handle);
120
121 _eglInitDisplay();
122
123 _eglHashRemove(_eglDisplayHash, key);
124 dpy->Handle = EGL_NO_DISPLAY;
125 }
126
127
128 /**
129 * Return the handle of a linked display, or EGL_NO_DISPLAY.
130 */
131 EGLDisplay
132 _eglGetDisplayHandle(_EGLDisplay *display)
133 {
134 if (display)
135 return display->Handle;
136 else
137 return EGL_NO_DISPLAY;
138 }
139
140
141 /**
142 * Lookup a handle to find the linked display.
143 * Return NULL if the handle has no corresponding linked display.
144 */
145 _EGLDisplay *
146 _eglLookupDisplay(EGLDisplay dpy)
147 {
148 EGLuint key = _eglPointerToUInt((void *) dpy);
149
150 _eglInitDisplay();
151
152 return (_EGLDisplay *) _eglHashLookup(_eglDisplayHash, key);
153 }
154
155
156 /**
157 * Find the display corresponding to the specified native display id in all
158 * linked displays.
159 */
160 _EGLDisplay *
161 _eglFindDisplay(NativeDisplayType nativeDisplay)
162 {
163 EGLuint key;
164
165 _eglInitDisplay();
166
167 /* Walk the hash table. Should switch to list if it is a problem. */
168 key = _eglHashFirstEntry(_eglDisplayHash);
169 while (key) {
170 _EGLDisplay *dpy = (_EGLDisplay *)
171 _eglHashLookup(_eglDisplayHash, key);
172 assert(dpy);
173
174 if (dpy->NativeDisplay == nativeDisplay)
175 return dpy;
176 key = _eglHashNextEntry(_eglDisplayHash, key);
177 }
178
179 return NULL;
180 }
181
182
183 /**
184 * Destroy the contexts and surfaces that are linked to the display.
185 */
186 void
187 _eglReleaseDisplayResources(_EGLDriver *drv, EGLDisplay dpy)
188 {
189 _EGLDisplay *display;
190 _EGLContext *contexts;
191 _EGLSurface *surfaces;
192
193 display = _eglLookupDisplay(dpy);
194 if (!display)
195 return;
196 contexts = display->ContextList;
197 surfaces = display->SurfaceList;
198
199 while (contexts) {
200 EGLContext handle = _eglGetContextHandle(contexts);
201 contexts = contexts->Next;
202 drv->API.DestroyContext(drv, dpy, handle);
203 }
204 assert(!display->ContextList);
205
206 while (surfaces) {
207 EGLSurface handle = _eglGetSurfaceHandle(surfaces);
208 surfaces = surfaces->Next;
209 drv->API.DestroySurface(drv, dpy, handle);
210 }
211 assert(!display->SurfaceList);
212 }
213
214
215 /**
216 * Free all the data hanging of an _EGLDisplay object, but not
217 * the object itself.
218 */
219 void
220 _eglCleanupDisplay(_EGLDisplay *disp)
221 {
222 EGLint i;
223
224 for (i = 0; i < disp->NumConfigs; i++) {
225 free(disp->Configs[i]);
226 }
227 free(disp->Configs);
228 disp->Configs = NULL;
229
230 /* XXX incomplete */
231
232 free((void *) disp->DriverName);
233 disp->DriverName = NULL;
234
235 /* driver deletes the _EGLDisplay object */
236 }
237
238
239 /**
240 * Link a context to a display and return the handle of the link.
241 * The handle can be passed to client directly.
242 */
243 EGLContext
244 _eglLinkContext(_EGLContext *ctx, _EGLDisplay *dpy)
245 {
246 ctx->Display = dpy;
247 ctx->Next = dpy->ContextList;
248 dpy->ContextList = ctx;
249 return (EGLContext) ctx;
250 }
251
252
253 /**
254 * Unlink a linked context from its display.
255 * Accessing an unlinked context should generate EGL_BAD_CONTEXT error.
256 */
257 void
258 _eglUnlinkContext(_EGLContext *ctx)
259 {
260 _EGLContext *prev;
261
262 prev = ctx->Display->ContextList;
263 if (prev != ctx) {
264 while (prev) {
265 if (prev->Next == ctx)
266 break;
267 prev = prev->Next;
268 }
269 assert(prev);
270 prev->Next = ctx->Next;
271 }
272 else {
273 ctx->Display->ContextList = ctx->Next;
274 }
275
276 ctx->Next = NULL;
277 ctx->Display = NULL;
278 }
279
280
281 /**
282 * Return the handle of a linked context, or EGL_NO_CONTEXT.
283 */
284 EGLContext
285 _eglGetContextHandle(_EGLContext *ctx)
286 {
287 return (EGLContext) ((ctx && ctx->Display) ? ctx : EGL_NO_CONTEXT);
288 }
289
290
291 /**
292 * Lookup a handle to find the linked context.
293 * Return NULL if the handle has no corresponding linked context.
294 */
295 _EGLContext *
296 _eglLookupContext(EGLContext ctx)
297 {
298 _EGLContext *context = (_EGLContext *) ctx;
299 return (context && context->Display) ? context : NULL;
300 }
301
302
303 /**
304 * Link a surface to a display and return the handle of the link.
305 * The handle can be passed to client directly.
306 */
307 EGLSurface
308 _eglLinkSurface(_EGLSurface *surf, _EGLDisplay *dpy)
309 {
310 EGLuint key;
311
312 surf->Display = dpy;
313 surf->Next = dpy->SurfaceList;
314 dpy->SurfaceList = surf;
315
316 key = _eglHashGenKey(dpy->SurfaceHash);
317 assert(key);
318 _eglHashInsert(dpy->SurfaceHash, key, surf);
319
320 surf->Handle = (EGLSurface) _eglUIntToPointer(key);
321 return surf->Handle;
322 }
323
324
325 /**
326 * Unlink a linked surface from its display.
327 * Accessing an unlinked surface should generate EGL_BAD_SURFACE error.
328 */
329 void
330 _eglUnlinkSurface(_EGLSurface *surf)
331 {
332 _EGLSurface *prev;
333 EGLuint key = _eglPointerToUInt((void *) surf->Handle);
334
335 _eglHashRemove(surf->Display->SurfaceHash, key);
336 surf->Handle = EGL_NO_SURFACE;
337
338 prev = surf->Display->SurfaceList;
339 if (prev != surf) {
340 while (prev) {
341 if (prev->Next == surf)
342 break;
343 prev = prev->Next;
344 }
345 assert(prev);
346 prev->Next = surf->Next;
347 }
348 else {
349 prev = NULL;
350 surf->Display->SurfaceList = surf->Next;
351 }
352
353 surf->Next = NULL;
354 surf->Display = NULL;
355 }
356
357
358 /**
359 * Return the handle of a linked surface, or EGL_NO_SURFACE.
360 */
361 EGLSurface
362 _eglGetSurfaceHandle(_EGLSurface *surface)
363 {
364 if (surface)
365 return surface->Handle;
366 else
367 return EGL_NO_SURFACE;
368 }
369
370
371 /**
372 * Lookup a handle to find the linked surface.
373 * Return NULL if the handle has no corresponding linked surface.
374 */
375 _EGLSurface *
376 _eglLookupSurface(EGLSurface surf)
377 {
378 EGLuint key = _eglPointerToUInt((void *) surf);
379 return (_EGLSurface *) _eglHashLookup(_eglSurfaceHash, key);
380 }