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