Merge remote branch 'origin/master' into nv50-compiler
[mesa.git] / src / gallium / targets / egl / egl.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include "util/u_debug.h"
30 #include "util/u_string.h"
31 #include "util/u_memory.h"
32 #include "util/u_dl.h"
33 #include "egldriver.h"
34 #include "egllog.h"
35
36 #include "state_tracker/st_api.h"
37 #include "state_tracker/drm_driver.h"
38 #include "common/egl_g3d_loader.h"
39
40 struct egl_g3d_loader egl_g3d_loader;
41
42 static struct st_module {
43 boolean initialized;
44 char *name;
45 struct util_dl_library *lib;
46 struct st_api *stapi;
47 } st_modules[ST_API_COUNT];
48
49 static struct pipe_module {
50 boolean initialized;
51 char *name;
52 struct util_dl_library *lib;
53 const struct drm_driver_descriptor *drmdd;
54 struct pipe_screen *(*swrast_create_screen)(struct sw_winsys *);
55 } pipe_modules[16];
56
57 static char *
58 loader_strdup(const char *s)
59 {
60 size_t len = (s) ? strlen(s) : 0;
61 char *t = MALLOC(len + 1);
62 if (t) {
63 memcpy(t, s, len);
64 t[len] = '\0';
65 }
66 return t;
67 }
68
69 static EGLBoolean
70 dlopen_st_module_cb(const char *dir, size_t len, void *callback_data)
71 {
72 struct st_module *stmod =
73 (struct st_module *) callback_data;
74 char path[1024];
75 int ret;
76
77 if (len) {
78 ret = util_snprintf(path, sizeof(path),
79 "%.*s/" ST_PREFIX "%s" UTIL_DL_EXT, len, dir, stmod->name);
80 }
81 else {
82 ret = util_snprintf(path, sizeof(path),
83 ST_PREFIX "%s" UTIL_DL_EXT, stmod->name);
84 }
85
86 if (ret > 0 && ret < sizeof(path)) {
87 stmod->lib = util_dl_open(path);
88 if (stmod->lib)
89 _eglLog(_EGL_DEBUG, "loaded %s", path);
90 }
91
92 return !(stmod->lib);
93 }
94
95 static boolean
96 load_st_module(struct st_module *stmod,
97 const char *name, const char *procname)
98 {
99 struct st_api *(*create_api)(void);
100
101 stmod->name = loader_strdup(name);
102 if (stmod->name)
103 _eglSearchPathForEach(dlopen_st_module_cb, (void *) stmod);
104 else
105 stmod->lib = util_dl_open(NULL);
106
107 if (stmod->lib) {
108 create_api = (struct st_api *(*)(void))
109 util_dl_get_proc_address(stmod->lib, procname);
110 if (create_api)
111 stmod->stapi = create_api();
112
113 if (!stmod->stapi) {
114 util_dl_close(stmod->lib);
115 stmod->lib = NULL;
116 }
117 }
118
119 if (!stmod->stapi) {
120 FREE(stmod->name);
121 stmod->name = NULL;
122 }
123
124 return (stmod->stapi != NULL);
125 }
126
127 static EGLBoolean
128 dlopen_pipe_module_cb(const char *dir, size_t len, void *callback_data)
129 {
130 struct pipe_module *pmod = (struct pipe_module *) callback_data;
131 char path[1024];
132 int ret;
133
134 if (len) {
135 ret = util_snprintf(path, sizeof(path),
136 "%.*s/" PIPE_PREFIX "%s" UTIL_DL_EXT, len, dir, pmod->name);
137 }
138 else {
139 ret = util_snprintf(path, sizeof(path),
140 PIPE_PREFIX "%s" UTIL_DL_EXT, pmod->name);
141 }
142 if (ret > 0 && ret < sizeof(path)) {
143 pmod->lib = util_dl_open(path);
144 if (pmod->lib)
145 _eglLog(_EGL_DEBUG, "loaded %s", path);
146 }
147
148 return !(pmod->lib);
149 }
150
151 static boolean
152 load_pipe_module(struct pipe_module *pmod, const char *name)
153 {
154 pmod->name = loader_strdup(name);
155 if (!pmod->name)
156 return FALSE;
157
158 _eglLog(_EGL_DEBUG, "searching for pipe module %s", pmod->name);
159 _eglSearchPathForEach(dlopen_pipe_module_cb, (void *) pmod);
160 if (pmod->lib) {
161 pmod->drmdd = (const struct drm_driver_descriptor *)
162 util_dl_get_proc_address(pmod->lib, "driver_descriptor");
163
164 /* sanity check on the name */
165 if (pmod->drmdd && strcmp(pmod->drmdd->name, pmod->name) != 0)
166 pmod->drmdd = NULL;
167
168 /* swrast */
169 if (pmod->drmdd && !pmod->drmdd->driver_name) {
170 pmod->swrast_create_screen =
171 (struct pipe_screen *(*)(struct sw_winsys *))
172 util_dl_get_proc_address(pmod->lib, "swrast_create_screen");
173 if (!pmod->swrast_create_screen)
174 pmod->drmdd = NULL;
175 }
176
177 if (!pmod->drmdd) {
178 util_dl_close(pmod->lib);
179 pmod->lib = NULL;
180 }
181 }
182
183 if (!pmod->drmdd)
184 pmod->name = NULL;
185
186 return (pmod->drmdd != NULL);
187 }
188
189 static struct st_api *
190 get_st_api(enum st_api_type api)
191 {
192 struct st_module *stmod = &st_modules[api];
193 const char *names[8], *symbol;
194 int i, count = 0;
195
196 if (stmod->initialized)
197 return stmod->stapi;
198
199 switch (api) {
200 case ST_API_OPENGL:
201 symbol = ST_CREATE_OPENGL_SYMBOL;
202 names[count++] = "GL";
203 break;
204 case ST_API_OPENGL_ES1:
205 symbol = ST_CREATE_OPENGL_ES1_SYMBOL;
206 names[count++] = "GLESv1_CM";
207 names[count++] = "GL";
208 break;
209 case ST_API_OPENGL_ES2:
210 symbol = ST_CREATE_OPENGL_ES2_SYMBOL;
211 names[count++] = "GLESv2";
212 names[count++] = "GL";
213 break;
214 case ST_API_OPENVG:
215 symbol = ST_CREATE_OPENVG_SYMBOL;
216 names[count++] = "OpenVG";
217 break;
218 default:
219 symbol = NULL;
220 assert(!"Unknown API Type\n");
221 break;
222 }
223
224 /* NULL means the process itself */
225 names[count++] = NULL;
226
227 for (i = 0; i < count; i++) {
228 if (load_st_module(stmod, names[i], symbol))
229 break;
230 }
231
232 if (!stmod->stapi) {
233 EGLint level = (egl_g3d_loader.api_mask & (1 << api)) ?
234 _EGL_WARNING : _EGL_DEBUG;
235 _eglLog(level, "unable to load " ST_PREFIX "%s" UTIL_DL_EXT, names[0]);
236 }
237
238 stmod->initialized = TRUE;
239
240 return stmod->stapi;
241 }
242
243 static struct st_api *
244 guess_gl_api(void)
245 {
246 struct st_api *stapi;
247 int gl_apis[] = {
248 ST_API_OPENGL,
249 ST_API_OPENGL_ES1,
250 ST_API_OPENGL_ES2,
251 -1
252 };
253 int i, api = -1;
254
255 /* determine the api from the loaded libraries */
256 for (i = 0; gl_apis[i] != -1; i++) {
257 if (st_modules[gl_apis[i]].stapi) {
258 api = gl_apis[i];
259 break;
260 }
261 }
262 /* determine the api from the linked libraries */
263 if (api == -1) {
264 struct util_dl_library *self = util_dl_open(NULL);
265
266 if (self) {
267 if (util_dl_get_proc_address(self, "glColor4d"))
268 api = ST_API_OPENGL;
269 else if (util_dl_get_proc_address(self, "glColor4x"))
270 api = ST_API_OPENGL_ES1;
271 else if (util_dl_get_proc_address(self, "glShaderBinary"))
272 api = ST_API_OPENGL_ES2;
273 util_dl_close(self);
274 }
275 }
276
277 stapi = (api != -1) ? get_st_api(api) : NULL;
278 if (!stapi) {
279 for (i = 0; gl_apis[i] != -1; i++) {
280 api = gl_apis[i];
281 stapi = get_st_api(api);
282 if (stapi)
283 break;
284 }
285 }
286
287 return stapi;
288 }
289
290 static struct pipe_module *
291 get_pipe_module(const char *name)
292 {
293 struct pipe_module *pmod = NULL;
294 int i;
295
296 if (!name)
297 return NULL;
298
299 for (i = 0; i < Elements(pipe_modules); i++) {
300 if (!pipe_modules[i].initialized ||
301 strcmp(pipe_modules[i].name, name) == 0) {
302 pmod = &pipe_modules[i];
303 break;
304 }
305 }
306 if (!pmod)
307 return NULL;
308
309 if (!pmod->initialized) {
310 load_pipe_module(pmod, name);
311 pmod->initialized = TRUE;
312 }
313
314 return pmod;
315 }
316
317 static struct pipe_screen *
318 create_drm_screen(const char *name, int fd)
319 {
320 struct pipe_module *pmod = get_pipe_module(name);
321 return (pmod && pmod->drmdd->create_screen) ?
322 pmod->drmdd->create_screen(fd) : NULL;
323 }
324
325 static struct pipe_screen *
326 create_sw_screen(struct sw_winsys *ws)
327 {
328 struct pipe_module *pmod = get_pipe_module("swrast");
329 return (pmod && pmod->swrast_create_screen) ?
330 pmod->swrast_create_screen(ws) : NULL;
331 }
332
333 static const struct egl_g3d_loader *
334 loader_init(void)
335 {
336 uint api_mask = 0x0;
337
338 /* TODO detect at runtime? */
339 #if FEATURE_GL
340 api_mask |= 1 << ST_API_OPENGL;
341 #endif
342 #if FEATURE_ES1
343 api_mask |= 1 << ST_API_OPENGL_ES1;
344 #endif
345 #if FEATURE_ES2
346 api_mask |= 1 << ST_API_OPENGL_ES2;
347 #endif
348 #if FEATURE_VG
349 api_mask |= 1 << ST_API_OPENVG;
350 #endif
351
352 egl_g3d_loader.api_mask = api_mask;
353 egl_g3d_loader.get_st_api = get_st_api;
354 egl_g3d_loader.guess_gl_api = guess_gl_api;
355 egl_g3d_loader.create_drm_screen = create_drm_screen;
356 egl_g3d_loader.create_sw_screen = create_sw_screen;
357
358 return &egl_g3d_loader;
359 }
360
361 static void
362 loader_fini(void)
363 {
364 int i;
365
366 for (i = 0; i < ST_API_COUNT; i++) {
367 struct st_module *stmod = &st_modules[i];
368
369 if (stmod->stapi) {
370 stmod->stapi->destroy(stmod->stapi);
371 stmod->stapi = NULL;
372 }
373 if (stmod->lib) {
374 util_dl_close(stmod->lib);
375 stmod->lib = NULL;
376 }
377 if (stmod->name) {
378 FREE(stmod->name);
379 stmod->name = NULL;
380 }
381 stmod->initialized = FALSE;
382 }
383 for (i = 0; i < Elements(pipe_modules); i++) {
384 struct pipe_module *pmod = &pipe_modules[i];
385
386 if (!pmod->initialized)
387 break;
388
389 pmod->drmdd = NULL;
390 pmod->swrast_create_screen = NULL;
391 if (pmod->lib) {
392 util_dl_close(pmod->lib);
393 pmod->lib = NULL;
394 }
395 if (pmod->name) {
396 FREE(pmod->name);
397 pmod->name = NULL;
398 }
399 pmod->initialized = FALSE;
400 }
401 }
402
403 static void
404 egl_g3d_unload(_EGLDriver *drv)
405 {
406 egl_g3d_destroy_driver(drv);
407 loader_fini();
408 }
409
410 _EGLDriver *
411 _eglMain(const char *args)
412 {
413 const struct egl_g3d_loader *loader;
414 _EGLDriver *drv;
415
416 loader = loader_init();
417 drv = egl_g3d_create_driver(loader);
418 if (!drv) {
419 loader_fini();
420 return NULL;
421 }
422
423 drv->Name = "Gallium";
424 drv->Unload = egl_g3d_unload;
425
426 return drv;
427 }