egl: Change the way drivers are loaded.
[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 = _eglPreloadDriver(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 *display)
204 {
205 _EGLContext *contexts;
206 _EGLSurface *surfaces;
207
208 contexts = display->ContextList;
209 surfaces = display->SurfaceList;
210
211 while (contexts) {
212 _EGLContext *ctx = contexts;
213 contexts = contexts->Next;
214
215 _eglUnlinkContext(ctx);
216 drv->API.DestroyContext(drv, display, ctx);
217 }
218 assert(!display->ContextList);
219
220 while (surfaces) {
221 _EGLSurface *surf = surfaces;
222 surfaces = surfaces->Next;
223
224 _eglUnlinkSurface(surf);
225 drv->API.DestroySurface(drv, display, surf);
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
249
250 /**
251 * Link a context to a display and return the handle of the link.
252 * The handle can be passed to client directly.
253 */
254 EGLContext
255 _eglLinkContext(_EGLContext *ctx, _EGLDisplay *dpy)
256 {
257 ctx->Display = dpy;
258 ctx->Next = dpy->ContextList;
259 dpy->ContextList = ctx;
260 return (EGLContext) ctx;
261 }
262
263
264 /**
265 * Unlink a linked context from its display.
266 * Accessing an unlinked context should generate EGL_BAD_CONTEXT error.
267 */
268 void
269 _eglUnlinkContext(_EGLContext *ctx)
270 {
271 _EGLContext *prev;
272
273 prev = ctx->Display->ContextList;
274 if (prev != ctx) {
275 while (prev) {
276 if (prev->Next == ctx)
277 break;
278 prev = prev->Next;
279 }
280 assert(prev);
281 prev->Next = ctx->Next;
282 }
283 else {
284 ctx->Display->ContextList = ctx->Next;
285 }
286
287 ctx->Next = NULL;
288 ctx->Display = NULL;
289 }
290
291
292 /**
293 * Return the handle of a linked context, or EGL_NO_CONTEXT.
294 */
295 EGLContext
296 _eglGetContextHandle(_EGLContext *ctx)
297 {
298 return (EGLContext) ((ctx && ctx->Display) ? ctx : EGL_NO_CONTEXT);
299 }
300
301
302 /**
303 * Lookup a handle to find the linked context.
304 * Return NULL if the handle has no corresponding linked context.
305 */
306 _EGLContext *
307 _eglLookupContext(EGLContext ctx, _EGLDisplay *dpy)
308 {
309 _EGLContext *context = (_EGLContext *) ctx;
310 return (context && context->Display) ? context : NULL;
311 }
312
313
314 /**
315 * Link a surface to a display and return the handle of the link.
316 * The handle can be passed to client directly.
317 */
318 EGLSurface
319 _eglLinkSurface(_EGLSurface *surf, _EGLDisplay *dpy)
320 {
321 EGLuint key;
322
323 surf->Display = dpy;
324 surf->Next = dpy->SurfaceList;
325 dpy->SurfaceList = surf;
326
327 key = _eglHashGenKey(dpy->SurfaceHash);
328 assert(key);
329 _eglHashInsert(dpy->SurfaceHash, key, surf);
330
331 surf->Handle = (EGLSurface) _eglUIntToPointer(key);
332 return surf->Handle;
333 }
334
335
336 /**
337 * Unlink a linked surface from its display.
338 * Accessing an unlinked surface should generate EGL_BAD_SURFACE error.
339 */
340 void
341 _eglUnlinkSurface(_EGLSurface *surf)
342 {
343 _EGLSurface *prev;
344 EGLuint key = _eglPointerToUInt((void *) surf->Handle);
345
346 _eglHashRemove(surf->Display->SurfaceHash, key);
347 surf->Handle = EGL_NO_SURFACE;
348
349 prev = surf->Display->SurfaceList;
350 if (prev != surf) {
351 while (prev) {
352 if (prev->Next == surf)
353 break;
354 prev = prev->Next;
355 }
356 assert(prev);
357 prev->Next = surf->Next;
358 }
359 else {
360 prev = NULL;
361 surf->Display->SurfaceList = surf->Next;
362 }
363
364 surf->Next = NULL;
365 surf->Display = NULL;
366 }
367
368
369 /**
370 * Return the handle of a linked surface, or EGL_NO_SURFACE.
371 */
372 EGLSurface
373 _eglGetSurfaceHandle(_EGLSurface *surface)
374 {
375 if (surface)
376 return surface->Handle;
377 else
378 return EGL_NO_SURFACE;
379 }
380
381
382 /**
383 * Lookup a handle to find the linked surface.
384 * Return NULL if the handle has no corresponding linked surface.
385 */
386 _EGLSurface *
387 _eglLookupSurface(EGLSurface surf, _EGLDisplay *dpy)
388 {
389 EGLuint key = _eglPointerToUInt((void *) surf);
390 return (_EGLSurface *) _eglHashLookup(dpy->SurfaceHash, key);
391 }