Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * Copyright 2009-2010 Chia-I Wu |
||
5 | * Copyright 2010-2011 LunarG, Inc. |
||
6 | * All Rights Reserved. |
||
7 | * |
||
8 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
9 | * copy of this software and associated documentation files (the |
||
10 | * "Software"), to deal in the Software without restriction, including |
||
11 | * without limitation the rights to use, copy, modify, merge, publish, |
||
12 | * distribute, sub license, and/or sell copies of the Software, and to |
||
13 | * permit persons to whom the Software is furnished to do so, subject to |
||
14 | * the following conditions: |
||
15 | * |
||
16 | * The above copyright notice and this permission notice (including the |
||
17 | * next paragraph) shall be included in all copies or substantial portions |
||
18 | * of the Software. |
||
19 | * |
||
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
23 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||
25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||
26 | * DEALINGS IN THE SOFTWARE. |
||
27 | * |
||
28 | **************************************************************************/ |
||
29 | |||
30 | |||
31 | /** |
||
32 | * Functions related to EGLDisplay. |
||
33 | */ |
||
34 | |||
35 | #include |
||
36 | #include |
||
37 | #include |
||
38 | #include "eglcontext.h" |
||
39 | #include "eglsurface.h" |
||
40 | #include "egldisplay.h" |
||
41 | #include "egldriver.h" |
||
42 | #include "eglglobals.h" |
||
43 | #include "eglmutex.h" |
||
44 | #include "egllog.h" |
||
45 | |||
46 | /* Includes for _eglNativePlatformDetectNativeDisplay */ |
||
47 | #ifdef HAVE_MINCORE |
||
48 | #include |
||
49 | #include |
||
50 | #endif |
||
51 | #ifdef HAVE_WAYLAND_PLATFORM |
||
52 | #include |
||
53 | #endif |
||
54 | #ifdef HAVE_DRM_PLATFORM |
||
55 | #include |
||
56 | #endif |
||
57 | #ifdef HAVE_FBDEV_PLATFORM |
||
58 | #include |
||
59 | #include |
||
60 | #include |
||
61 | #endif |
||
62 | |||
63 | |||
64 | /** |
||
65 | * Map --with-egl-platforms names to platform types. |
||
66 | */ |
||
67 | static const struct { |
||
68 | _EGLPlatformType platform; |
||
69 | const char *name; |
||
70 | } egl_platforms[_EGL_NUM_PLATFORMS] = { |
||
71 | { _EGL_PLATFORM_DRM, "drm" } |
||
72 | }; |
||
73 | |||
74 | |||
75 | /** |
||
76 | * Return the native platform by parsing EGL_PLATFORM. |
||
77 | */ |
||
78 | static _EGLPlatformType |
||
79 | _eglGetNativePlatformFromEnv(void) |
||
80 | { |
||
81 | _EGLPlatformType plat = _EGL_INVALID_PLATFORM; |
||
82 | const char *plat_name; |
||
83 | EGLint i; |
||
84 | |||
85 | plat_name = getenv("EGL_PLATFORM"); |
||
86 | /* try deprecated env variable */ |
||
87 | if (!plat_name || !plat_name[0]) |
||
88 | plat_name = getenv("EGL_DISPLAY"); |
||
89 | if (!plat_name || !plat_name[0]) |
||
90 | return _EGL_INVALID_PLATFORM; |
||
91 | |||
92 | for (i = 0; i < _EGL_NUM_PLATFORMS; i++) { |
||
93 | if (strcmp(egl_platforms[i].name, plat_name) == 0) { |
||
94 | plat = egl_platforms[i].platform; |
||
95 | break; |
||
96 | } |
||
97 | } |
||
98 | |||
99 | return plat; |
||
100 | } |
||
101 | |||
102 | |||
103 | /** |
||
104 | * Perform validity checks on a generic pointer. |
||
105 | */ |
||
106 | static EGLBoolean |
||
107 | _eglPointerIsDereferencable(void *p) |
||
108 | { |
||
109 | #ifdef HAVE_MINCORE |
||
110 | uintptr_t addr = (uintptr_t) p; |
||
111 | unsigned char valid = 0; |
||
112 | const long page_size = getpagesize(); |
||
113 | |||
114 | if (p == NULL) |
||
115 | return EGL_FALSE; |
||
116 | |||
117 | /* align addr to page_size */ |
||
118 | addr &= ~(page_size - 1); |
||
119 | |||
120 | if (mincore((void *) addr, page_size, &valid) < 0) { |
||
121 | _eglLog(_EGL_DEBUG, "mincore failed: %m"); |
||
122 | return EGL_FALSE; |
||
123 | } |
||
124 | |||
125 | return (valid & 0x01) == 0x01; |
||
126 | #else |
||
127 | return p != NULL; |
||
128 | #endif |
||
129 | } |
||
130 | |||
131 | |||
132 | /** |
||
133 | * Try detecting native platform with the help of native display characteristcs. |
||
134 | */ |
||
135 | static _EGLPlatformType |
||
136 | _eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay) |
||
137 | { |
||
138 | return _EGL_PLATFORM_DRM; |
||
139 | } |
||
140 | |||
141 | |||
142 | /** |
||
143 | * Return the native platform. It is the platform of the EGL native types. |
||
144 | */ |
||
145 | _EGLPlatformType |
||
146 | _eglGetNativePlatform(EGLNativeDisplayType nativeDisplay) |
||
147 | { |
||
148 | return _EGL_PLATFORM_DRM; |
||
149 | } |
||
150 | |||
151 | |||
152 | /** |
||
153 | * Finish display management. |
||
154 | */ |
||
155 | void |
||
156 | _eglFiniDisplay(void) |
||
157 | { |
||
158 | _EGLDisplay *dpyList, *dpy; |
||
159 | |||
160 | /* atexit function is called with global mutex locked */ |
||
161 | dpyList = _eglGlobal.DisplayList; |
||
162 | while (dpyList) { |
||
163 | EGLint i; |
||
164 | |||
165 | /* pop list head */ |
||
166 | dpy = dpyList; |
||
167 | dpyList = dpyList->Next; |
||
168 | |||
169 | for (i = 0; i < _EGL_NUM_RESOURCES; i++) { |
||
170 | if (dpy->ResourceLists[i]) { |
||
171 | _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy); |
||
172 | break; |
||
173 | } |
||
174 | } |
||
175 | |||
176 | free(dpy); |
||
177 | } |
||
178 | _eglGlobal.DisplayList = NULL; |
||
179 | } |
||
180 | |||
181 | |||
182 | /** |
||
183 | * Find the display corresponding to the specified native display, or create a |
||
184 | * new one. |
||
185 | */ |
||
186 | _EGLDisplay * |
||
187 | _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) |
||
188 | { |
||
189 | _EGLDisplay *dpy; |
||
190 | |||
191 | if (plat == _EGL_INVALID_PLATFORM) |
||
192 | return NULL; |
||
193 | |||
194 | _eglLockMutex(_eglGlobal.Mutex); |
||
195 | |||
196 | /* search the display list first */ |
||
197 | dpy = _eglGlobal.DisplayList; |
||
198 | while (dpy) { |
||
199 | if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy) |
||
200 | break; |
||
201 | dpy = dpy->Next; |
||
202 | } |
||
203 | |||
204 | /* create a new display */ |
||
205 | if (!dpy) { |
||
206 | dpy = calloc(1, sizeof(_EGLDisplay)); |
||
207 | if (dpy) { |
||
208 | _eglInitMutex(&dpy->Mutex); |
||
209 | dpy->Platform = plat; |
||
210 | dpy->PlatformDisplay = plat_dpy; |
||
211 | |||
212 | /* add to the display list */ |
||
213 | dpy->Next = _eglGlobal.DisplayList; |
||
214 | _eglGlobal.DisplayList = dpy; |
||
215 | } |
||
216 | } |
||
217 | |||
218 | _eglUnlockMutex(_eglGlobal.Mutex); |
||
219 | |||
220 | return dpy; |
||
221 | } |
||
222 | |||
223 | |||
224 | /** |
||
225 | * Destroy the contexts and surfaces that are linked to the display. |
||
226 | */ |
||
227 | void |
||
228 | _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display) |
||
229 | { |
||
230 | _EGLResource *list; |
||
231 | |||
232 | list = display->ResourceLists[_EGL_RESOURCE_CONTEXT]; |
||
233 | while (list) { |
||
234 | _EGLContext *ctx = (_EGLContext *) list; |
||
235 | list = list->Next; |
||
236 | |||
237 | _eglUnlinkContext(ctx); |
||
238 | drv->API.DestroyContext(drv, display, ctx); |
||
239 | } |
||
240 | assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]); |
||
241 | |||
242 | list = display->ResourceLists[_EGL_RESOURCE_SURFACE]; |
||
243 | while (list) { |
||
244 | _EGLSurface *surf = (_EGLSurface *) list; |
||
245 | list = list->Next; |
||
246 | |||
247 | _eglUnlinkSurface(surf); |
||
248 | drv->API.DestroySurface(drv, display, surf); |
||
249 | } |
||
250 | assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]); |
||
251 | } |
||
252 | |||
253 | |||
254 | /** |
||
255 | * Free all the data hanging of an _EGLDisplay object, but not |
||
256 | * the object itself. |
||
257 | */ |
||
258 | void |
||
259 | _eglCleanupDisplay(_EGLDisplay *disp) |
||
260 | { |
||
261 | if (disp->Configs) { |
||
262 | _eglDestroyArray(disp->Configs, free); |
||
263 | disp->Configs = NULL; |
||
264 | } |
||
265 | |||
266 | /* XXX incomplete */ |
||
267 | } |
||
268 | |||
269 | |||
270 | /** |
||
271 | * Return EGL_TRUE if the given handle is a valid handle to a display. |
||
272 | */ |
||
273 | EGLBoolean |
||
274 | _eglCheckDisplayHandle(EGLDisplay dpy) |
||
275 | { |
||
276 | _EGLDisplay *cur; |
||
277 | |||
278 | _eglLockMutex(_eglGlobal.Mutex); |
||
279 | cur = _eglGlobal.DisplayList; |
||
280 | while (cur) { |
||
281 | if (cur == (_EGLDisplay *) dpy) |
||
282 | break; |
||
283 | cur = cur->Next; |
||
284 | } |
||
285 | _eglUnlockMutex(_eglGlobal.Mutex); |
||
286 | return (cur != NULL); |
||
287 | } |
||
288 | |||
289 | |||
290 | /** |
||
291 | * Return EGL_TRUE if the given resource is valid. That is, the display does |
||
292 | * own the resource. |
||
293 | */ |
||
294 | EGLBoolean |
||
295 | _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy) |
||
296 | { |
||
297 | _EGLResource *list = dpy->ResourceLists[type]; |
||
298 | |||
299 | if (!res) |
||
300 | return EGL_FALSE; |
||
301 | |||
302 | while (list) { |
||
303 | if (res == (void *) list) { |
||
304 | assert(list->Display == dpy); |
||
305 | break; |
||
306 | } |
||
307 | list = list->Next; |
||
308 | } |
||
309 | |||
310 | return (list != NULL); |
||
311 | } |
||
312 | |||
313 | |||
314 | /** |
||
315 | * Initialize a display resource. |
||
316 | */ |
||
317 | void |
||
318 | _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy) |
||
319 | { |
||
320 | memset(res, 0, size); |
||
321 | res->Display = dpy; |
||
322 | res->RefCount = 1; |
||
323 | } |
||
324 | |||
325 | |||
326 | /** |
||
327 | * Increment reference count for the resource. |
||
328 | */ |
||
329 | void |
||
330 | _eglGetResource(_EGLResource *res) |
||
331 | { |
||
332 | assert(res && res->RefCount > 0); |
||
333 | /* hopefully a resource is always manipulated with its display locked */ |
||
334 | res->RefCount++; |
||
335 | } |
||
336 | |||
337 | |||
338 | /** |
||
339 | * Decrement reference count for the resource. |
||
340 | */ |
||
341 | EGLBoolean |
||
342 | _eglPutResource(_EGLResource *res) |
||
343 | { |
||
344 | assert(res && res->RefCount > 0); |
||
345 | res->RefCount--; |
||
346 | return (!res->RefCount); |
||
347 | } |
||
348 | |||
349 | |||
350 | /** |
||
351 | * Link a resource to its display. |
||
352 | */ |
||
353 | void |
||
354 | _eglLinkResource(_EGLResource *res, _EGLResourceType type) |
||
355 | { |
||
356 | assert(res->Display); |
||
357 | |||
358 | res->IsLinked = EGL_TRUE; |
||
359 | res->Next = res->Display->ResourceLists[type]; |
||
360 | res->Display->ResourceLists[type] = res; |
||
361 | _eglGetResource(res); |
||
362 | } |
||
363 | |||
364 | |||
365 | /** |
||
366 | * Unlink a linked resource from its display. |
||
367 | */ |
||
368 | void |
||
369 | _eglUnlinkResource(_EGLResource *res, _EGLResourceType type) |
||
370 | { |
||
371 | _EGLResource *prev; |
||
372 | |||
373 | prev = res->Display->ResourceLists[type]; |
||
374 | if (prev != res) { |
||
375 | while (prev) { |
||
376 | if (prev->Next == res) |
||
377 | break; |
||
378 | prev = prev->Next; |
||
379 | } |
||
380 | assert(prev); |
||
381 | prev->Next = res->Next; |
||
382 | } |
||
383 | else { |
||
384 | res->Display->ResourceLists[type] = res->Next; |
||
385 | } |
||
386 | |||
387 | res->Next = NULL; |
||
388 | res->IsLinked = EGL_FALSE; |
||
389 | _eglPutResource(res); |
||
390 | |||
391 | /* We always unlink before destroy. The driver still owns a reference */ |
||
392 | assert(res->RefCount); |
||
393 | }>>> |