1 /*
2 * Copyright (c) 2013, NVIDIA CORPORATION.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and/or associated documentation files (the
6 * "Materials"), to deal in the Materials without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Materials, and to
9 * permit persons to whom the Materials are furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * unaltered in all copies or substantial portions of the Materials.
14 * Any additions, deletions, or changes to the original source files
15 * must be clearly indicated in accompanying documentation.
16 *
17 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
24 */
25
26 #include <pthread.h>
27 #include <string.h>
28
29 #if defined(HASH_DEBUG)
30 # include <stdio.h>
31 #endif
32
33 #include "libeglcurrent.h"
34 #include "libeglmapping.h"
35 #include "glvnd_pthread.h"
36 #include "egldispatchstubs.h"
37 #include "utils_misc.h"
38 #include "trace.h"
39
40 #include "lkdhash.h"
41
42 static glvnd_mutex_t dispatchIndexMutex = GLVND_MUTEX_INITIALIZER;
43
44 typedef struct __EGLdeviceInfoRec {
45 EGLDeviceEXT handle;
46 __EGLvendorInfo *vendor;
47 UT_hash_handle hh;
48 } __EGLdeviceInfo;
49 static DEFINE_INITIALIZED_LKDHASH(__EGLdeviceInfo, __eglDeviceHash);
50
51 /****************************************************************************/
52
53 typedef struct __EGLdisplayInfoHashRec {
54 __EGLdisplayInfo info;
55 UT_hash_handle hh;
56 } __EGLdisplayInfoHash;
57
58 static DEFINE_INITIALIZED_LKDHASH(__EGLdisplayInfoHash, __eglDisplayInfoHash);
59
__eglGetEGLDispatchAddress(const char * procName)60 __eglMustCastToProperFunctionPointerType __eglGetEGLDispatchAddress(const char *procName)
61 {
62 struct glvnd_list *vendorList = __eglLoadVendors();
63 __EGLvendorInfo *vendor;
64 __eglMustCastToProperFunctionPointerType addr = NULL;
65 int index;
66
67 __glvndPthreadFuncs.mutex_lock(&dispatchIndexMutex);
68
69 index = __glvndWinsysDispatchFindIndex(procName);
70 if (index >= 0) {
71 addr = (__eglMustCastToProperFunctionPointerType) __glvndWinsysDispatchGetDispatch(index);
72 __glvndPthreadFuncs.mutex_unlock(&dispatchIndexMutex);
73 return addr;
74 }
75
76 // Check each vendor library for a dispatch stub.
77 glvnd_list_for_each_entry(vendor, vendorList, entry) {
78 addr = vendor->eglvc.getDispatchAddress(procName);
79 if (addr != NULL) {
80 break;
81 }
82 }
83 if (addr != NULL) {
84 index = __glvndWinsysDispatchAllocIndex(procName, addr);
85 if (index >= 0) {
86 glvnd_list_for_each_entry(vendor, vendorList, entry) {
87 vendor->eglvc.setDispatchIndex(procName, index);
88 }
89 } else {
90 addr = NULL;
91 }
92 }
93
94 __glvndPthreadFuncs.mutex_unlock(&dispatchIndexMutex);
95 return addr;
96 }
97
__eglFetchDispatchEntry(__EGLvendorInfo * vendor,int index)98 __eglMustCastToProperFunctionPointerType __eglFetchDispatchEntry(
99 __EGLvendorInfo *vendor, int index)
100 {
101 __eglMustCastToProperFunctionPointerType addr = NULL;
102 const char *procName = NULL;
103
104 addr = (__eglMustCastToProperFunctionPointerType)
105 __glvndWinsysVendorDispatchLookupFunc(vendor->dynDispatch, index);
106 if (addr != NULL) {
107 return addr;
108 }
109
110 // Not seen before by this vendor: query the vendor for the right
111 // address to use.
112
113 __glvndPthreadFuncs.mutex_lock(&dispatchIndexMutex);
114 procName = __glvndWinsysDispatchGetName(index);
115 __glvndPthreadFuncs.mutex_unlock(&dispatchIndexMutex);
116
117 if (procName == NULL) {
118 // Not a valid function index.
119 return NULL;
120 }
121
122 // Get the real address.
123 addr = vendor->eglvc.getProcAddress(procName);
124 if (addr != NULL) {
125 // Record the address in the vendor's hashtable. Note that if this
126 // fails, it's not fatal. It just means we'll have to call
127 // getProcAddress again the next time we need this function.
128 __glvndWinsysVendorDispatchAddFunc(vendor->dynDispatch, index, addr);
129 }
130 return addr;
131 }
132
__eglGetVendorFromDisplay(EGLDisplay dpy)133 __EGLvendorInfo *__eglGetVendorFromDisplay(EGLDisplay dpy)
134 {
135 __EGLdisplayInfo *dpyInfo = __eglLookupDisplay(dpy);
136 if (dpyInfo != NULL) {
137 return dpyInfo->vendor;
138 } else {
139 return NULL;
140 }
141 }
142
143 /**
144 * Allocates and initializes a __EGLdisplayInfoHash structure.
145 *
146 * The caller is responsible for adding the structure to the hashtable.
147 *
148 * \param dpy The display connection.
149 * \return A newly-allocated __EGLdisplayInfoHash structure, or NULL on error.
150 */
InitDisplayInfoEntry(EGLDisplay dpy,__EGLvendorInfo * vendor)151 static __EGLdisplayInfoHash *InitDisplayInfoEntry(EGLDisplay dpy, __EGLvendorInfo *vendor)
152 {
153 __EGLdisplayInfoHash *pEntry;
154
155 pEntry = (__EGLdisplayInfoHash *) calloc(1, sizeof(*pEntry));
156 if (pEntry == NULL) {
157 return NULL;
158 }
159
160 pEntry->info.dpy = dpy;
161 pEntry->info.vendor = vendor;
162
163 return pEntry;
164 }
165
__eglLookupDisplay(EGLDisplay dpy)166 __EGLdisplayInfo *__eglLookupDisplay(EGLDisplay dpy)
167 {
168 __EGLdisplayInfoHash *pEntry = NULL;
169
170 if (dpy == EGL_NO_DISPLAY) {
171 return NULL;
172 }
173
174 LKDHASH_RDLOCK(__eglDisplayInfoHash);
175 HASH_FIND_PTR(_LH(__eglDisplayInfoHash), &dpy, pEntry);
176 LKDHASH_UNLOCK(__eglDisplayInfoHash);
177
178 if (pEntry != NULL) {
179 return &pEntry->info;
180 } else {
181 return NULL;
182 }
183 }
184
__eglAddDisplay(EGLDisplay dpy,__EGLvendorInfo * vendor)185 __EGLdisplayInfo *__eglAddDisplay(EGLDisplay dpy, __EGLvendorInfo *vendor)
186 {
187 __EGLdisplayInfoHash *pEntry = NULL;
188
189 if (dpy == EGL_NO_DISPLAY) {
190 return NULL;
191 }
192
193 LKDHASH_WRLOCK(__eglDisplayInfoHash);
194 HASH_FIND_PTR(_LH(__eglDisplayInfoHash), &dpy, pEntry);
195 if (pEntry == NULL) {
196 pEntry = InitDisplayInfoEntry(dpy, vendor);
197 if (pEntry != NULL) {
198 HASH_ADD_PTR(_LH(__eglDisplayInfoHash), info.dpy, pEntry);
199 }
200 }
201
202 LKDHASH_UNLOCK(__eglDisplayInfoHash);
203 if (pEntry != NULL && pEntry->info.vendor == vendor) {
204 return &pEntry->info;
205 } else {
206 return NULL;
207 }
208 }
209
__eglFreeDisplay(EGLDisplay dpy)210 void __eglFreeDisplay(EGLDisplay dpy)
211 {
212 __EGLdisplayInfoHash *pEntry = NULL;
213
214 LKDHASH_WRLOCK(__eglDisplayInfoHash);
215 HASH_FIND_PTR(_LH(__eglDisplayInfoHash), &dpy, pEntry);
216 if (pEntry != NULL) {
217 HASH_DEL(_LH(__eglDisplayInfoHash), pEntry);
218 }
219 LKDHASH_UNLOCK(__eglDisplayInfoHash);
220
221 if (pEntry != NULL) {
222 free(pEntry);
223 }
224 }
225
__eglMappingInit(void)226 void __eglMappingInit(void)
227 {
228 int i;
229 __eglInitDispatchStubs(&__eglExportsTable);
230 for (i=0; i<__EGL_DISPATCH_FUNC_COUNT; i++) {
231 int index = __glvndWinsysDispatchAllocIndex(
232 __EGL_DISPATCH_FUNC_NAMES[i],
233 __EGL_DISPATCH_FUNCS[i]);
234 if (index < 0) {
235 fprintf(stderr, "Could not allocate dispatch index array\n");
236 abort();
237 }
238 __EGL_DISPATCH_FUNC_INDICES[i] = index;
239 }
240 }
241
__eglMappingTeardown(EGLBoolean doReset)242 void __eglMappingTeardown(EGLBoolean doReset)
243 {
244 if (doReset) {
245 //__EGLdisplayInfoHash *dpyInfoEntry, *dpyInfoTmp;
246
247 /*
248 * If we're just doing fork recovery, we don't actually want to unload
249 * any currently loaded vendors _or_ remove any mappings (they should
250 * still be valid in the new process, and may be needed if the child
251 * tries using pointers/XIDs that were created in the parent). Just
252 * reset the corresponding locks.
253 */
254 __glvndPthreadFuncs.mutex_init(&dispatchIndexMutex, NULL);
255 __glvndPthreadFuncs.rwlock_init(&__eglDisplayInfoHash.lock, NULL);
256 } else {
257 /* Tear down all hashtables used in this file */
258 LKDHASH_TEARDOWN(__EGLdisplayInfoHash,
259 __eglDisplayInfoHash, NULL, NULL, EGL_FALSE);
260
261 LKDHASH_TEARDOWN(__EGLdeviceInfo,
262 __eglDeviceHash, NULL, NULL, EGL_FALSE);
263
264 __glvndWinsysDispatchCleanup();
265 }
266 }
267
__eglAddDevice(EGLDeviceEXT dev,__EGLvendorInfo * vendor)268 EGLBoolean __eglAddDevice(EGLDeviceEXT dev, __EGLvendorInfo *vendor)
269 {
270 __EGLdeviceInfo *devInfo = NULL;
271
272 if (dev == EGL_NO_DEVICE_EXT) {
273 // If the handle is NULL, then just silently ignore it.
274 return EGL_TRUE;
275 }
276
277 LKDHASH_WRLOCK(__eglDeviceHash);
278 HASH_FIND_PTR(_LH(__eglDeviceHash), &dev, devInfo);
279 if (devInfo == NULL) {
280 devInfo = malloc(sizeof(__EGLdeviceInfo));
281 if (devInfo == NULL) {
282 LKDHASH_UNLOCK(__eglDeviceHash);
283 return EGL_FALSE;
284 }
285 devInfo->handle = dev;
286 HASH_ADD_PTR(_LH(__eglDeviceHash), handle, devInfo);
287 }
288 devInfo->vendor = vendor;
289 LKDHASH_UNLOCK(__eglDeviceHash);
290 return EGL_TRUE;
291 }
292
__eglGetVendorFromDevice(EGLDeviceEXT dev)293 __EGLvendorInfo *__eglGetVendorFromDevice(EGLDeviceEXT dev)
294 {
295 __EGLdeviceInfo *devInfo;
296 __EGLvendorInfo *vendor = NULL;
297
298 LKDHASH_RDLOCK(__eglDeviceHash);
299 HASH_FIND_PTR(_LH(__eglDeviceHash), &dev, devInfo);
300 if (devInfo != NULL) {
301 vendor = devInfo->vendor;
302 } else {
303 vendor = NULL;
304 }
305 LKDHASH_UNLOCK(__eglDeviceHash);
306
307 return vendor;
308 }
309
310