Subversion Repositories Kolibri OS

Rev

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 for choosing and opening/loading device drivers.
33
 */
34
 
35
 
36
#include 
37
#include 
38
#include 
39
#include 
40
 
41
#include "eglstring.h"
42
#include "egldefines.h"
43
#include "egldisplay.h"
44
#include "egldriver.h"
45
#include "egllog.h"
46
#include "eglmutex.h"
47
 
48
typedef unsigned int lib_handle;
49
 
50
lib_handle load_library(const char *name);
51
void *get_proc_address(lib_handle lib, char *proc_name);
52
 
53
 
54
typedef struct _egl_module {
55
   char *Path;
56
   _EGLMain_t BuiltIn;
57
   void *Handle;
58
   _EGLDriver *Driver;
59
} _EGLModule;
60
 
61
static _EGL_DECLARE_MUTEX(_eglModuleMutex);
62
static _EGLArray *_eglModules;
63
 
64
const struct {
65
   const char *name;
66
   _EGLMain_t main;
67
} _eglBuiltInDrivers[] = {
68
#ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
69
   { "egl_gallium", _eglBuiltInDriverGALLIUM },
70
#endif
71
#ifdef _EGL_BUILT_IN_DRIVER_DRI2
72
   { "egl_dri2", _eglBuiltInDriverDRI2 },
73
#endif
74
#ifdef _EGL_BUILT_IN_DRIVER_GLX
75
   { "egl_glx", _eglBuiltInDriverGLX },
76
#endif
77
   { NULL, NULL }
78
};
79
 
80
/**
81
 * Wrappers for dlopen/dlclose()
82
 */
83
#if defined(_EGL_OS_WINDOWS)
84
 
85
 
86
typedef HMODULE lib_handle;
87
 
88
static HMODULE
89
open_library(const char *filename)
90
{
91
   return LoadLibrary(filename);
92
}
93
 
94
static void
95
close_library(HMODULE lib)
96
{
97
   FreeLibrary(lib);
98
}
99
 
100
 
101
static const char *
102
library_suffix(void)
103
{
104
   return ".dll";
105
}
106
 
107
 
108
#elif defined(_EGL_OS_UNIX)
109
 
110
 
111
typedef void * lib_handle;
112
 
113
static void *
114
open_library(const char *filename)
115
{
116
   return dlopen(filename, RTLD_LAZY);
117
}
118
 
119
static void
120
close_library(void *lib)
121
{
122
   dlclose(lib);
123
}
124
 
125
 
126
static const char *
127
library_suffix(void)
128
{
129
   return ".so";
130
}
131
 
132
 
133
#endif
134
 
135
/**
136
 * Open the named driver and find its bootstrap function: _eglMain().
137
 */
138
static _EGLMain_t
139
_eglOpenLibrary(const char *driverPath, lib_handle *handle)
140
{
141
   lib_handle lib;
142
   _EGLMain_t mainFunc = NULL;
143
   const char *error = "unknown error";
144
 
145
   assert(driverPath);
146
 
147
   _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
148
   lib = load_library(driverPath);
149
   if (!lib) {
150
      _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
151
              driverPath, error);
152
      return NULL;
153
   }
154
 
155
   mainFunc = (_EGLMain_t) get_proc_address(lib, "_eglMain");
156
 
157
   if (!mainFunc) {
158
      _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
159
              driverPath, error);
160
      return NULL;
161
   }
162
 
163
   *handle = lib;
164
   return mainFunc;
165
}
166
 
167
 
168
/**
169
 * Load a module and create the driver object.
170
 */
171
static EGLBoolean
172
_eglLoadModule(_EGLModule *mod)
173
{
174
   _EGLMain_t mainFunc;
175
   lib_handle lib;
176
   _EGLDriver *drv;
177
 
178
   if (mod->Driver)
179
      return EGL_TRUE;
180
 
181
   if (mod->BuiltIn) {
182
      lib = (lib_handle) NULL;
183
      mainFunc = mod->BuiltIn;
184
   }
185
   else {
186
      mainFunc = _eglOpenLibrary(mod->Path, &lib);
187
      if (!mainFunc)
188
         return EGL_FALSE;
189
   }
190
 
191
   drv = mainFunc(NULL);
192
   if (!drv) {
193
      return EGL_FALSE;
194
   }
195
 
196
   if (!drv->Name) {
197
      _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
198
      drv->Name = "UNNAMED";
199
   }
200
 
201
   mod->Handle = (void *) lib;
202
   mod->Driver = drv;
203
 
204
   return EGL_TRUE;
205
}
206
 
207
 
208
/**
209
 * Unload a module.
210
 */
211
static void
212
_eglUnloadModule(_EGLModule *mod)
213
{
214
#if defined(_EGL_OS_UNIX)
215
   /* destroy the driver */
216
   if (mod->Driver && mod->Driver->Unload)
217
      mod->Driver->Unload(mod->Driver);
218
 
219
   /*
220
    * XXX At this point (atexit), the module might be the last reference to
221
    * libEGL.  Closing the module might unmap libEGL and give problems.
222
    */
223
#if 0
224
   if (mod->Handle)
225
      close_library(mod->Handle);
226
#endif
227
#elif defined(_EGL_OS_WINDOWS)
228
   /* XXX Windows unloads DLLs before atexit */
229
#endif
230
 
231
   mod->Driver = NULL;
232
   mod->Handle = NULL;
233
}
234
 
235
 
236
/**
237
 * Add a module to the module array.
238
 */
239
static _EGLModule *
240
_eglAddModule(const char *path)
241
{
242
   _EGLModule *mod;
243
   EGLint i;
244
 
245
   if (!_eglModules) {
246
      _eglModules = _eglCreateArray("Module", 8);
247
      if (!_eglModules)
248
         return NULL;
249
   }
250
 
251
   /* find duplicates */
252
   for (i = 0; i < _eglModules->Size; i++) {
253
      mod = _eglModules->Elements[i];
254
      if (strcmp(mod->Path, path) == 0)
255
         return mod;
256
   }
257
 
258
   /* allocate a new one */
259
   mod = calloc(1, sizeof(*mod));
260
   if (mod) {
261
      mod->Path = _eglstrdup(path);
262
      if (!mod->Path) {
263
         free(mod);
264
         mod = NULL;
265
      }
266
   }
267
   if (mod) {
268
      _eglAppendArray(_eglModules, (void *) mod);
269
      _eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
270
   }
271
 
272
   return mod;
273
}
274
 
275
 
276
/**
277
 * Free a module.
278
 */
279
static void
280
_eglFreeModule(void *module)
281
{
282
   _EGLModule *mod = (_EGLModule *) module;
283
 
284
   _eglUnloadModule(mod);
285
   free(mod->Path);
286
   free(mod);
287
}
288
 
289
#if 0
290
/**
291
 * A loader function for use with _eglPreloadForEach.  The loader data is the
292
 * filename of the driver.   This function stops on the first valid driver.
293
 */
294
static EGLBoolean
295
_eglLoaderFile(const char *dir, size_t len, void *loader_data)
296
{
297
   char path[1024];
298
   const char *filename = (const char *) loader_data;
299
   size_t flen = strlen(filename);
300
 
301
   /* make a full path */
302
   if (len + flen + 2 > sizeof(path))
303
      return EGL_TRUE;
304
   if (len) {
305
      memcpy(path, dir, len);
306
      path[len++] = '/';
307
   }
308
   memcpy(path + len, filename, flen);
309
   len += flen;
310
   path[len] = '\0';
311
 
312
   if (library_suffix()) {
313
      const char *suffix = library_suffix();
314
      size_t slen = strlen(suffix);
315
      const char *p;
316
      EGLBoolean need_suffix;
317
 
318
      p = filename + flen - slen;
319
      need_suffix = (p < filename || strcmp(p, suffix) != 0);
320
      if (need_suffix) {
321
         /* overflow */
322
         if (len + slen + 1 > sizeof(path))
323
            return EGL_TRUE;
324
         strcpy(path + len, suffix);
325
      }
326
   }
327
 
328
#if defined(_EGL_OS_UNIX)
329
   /* check if the file exists */
330
   if (access(path, F_OK))
331
      return EGL_TRUE;
332
#endif
333
 
334
   _eglAddModule(path);
335
 
336
   return EGL_TRUE;
337
}
338
 
339
 
340
/**
341
 * Run the callback function on each driver directory.
342
 *
343
 * The process may end prematurely if the callback function returns false.
344
 */
345
static void
346
_eglPreloadForEach(const char *search_path,
347
                   EGLBoolean (*loader)(const char *, size_t, void *),
348
                   void *loader_data)
349
{
350
   const char *cur, *next;
351
   size_t len;
352
 
353
   cur = search_path;
354
   while (cur) {
355
      next = strchr(cur, ':');
356
      len = (next) ? next - cur : strlen(cur);
357
 
358
      if (!loader(cur, len, loader_data))
359
         break;
360
 
361
      cur = (next) ? next + 1 : NULL;
362
   }
363
}
364
 
365
 
366
/**
367
 * Return a list of colon-separated driver directories.
368
 */
369
static const char *
370
_eglGetSearchPath(void)
371
{
372
   static char search_path[1024];
373
 
374
#if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
375
   if (search_path[0] == '\0') {
376
      char *buf = search_path;
377
      size_t len = sizeof(search_path);
378
      EGLBoolean use_env;
379
      char dir_sep;
380
      int ret;
381
 
382
#if defined(_EGL_OS_UNIX)
383
      use_env = (geteuid() == getuid() && getegid() == getgid());
384
      dir_sep = '/';
385
#else
386
      use_env = EGL_TRUE;
387
      dir_sep = '\\';
388
#endif
389
 
390
      if (use_env) {
391
         char *p;
392
 
393
         /* extract the dirname from EGL_DRIVER */
394
         p = getenv("EGL_DRIVER");
395
         if (p && strchr(p, dir_sep)) {
396
            ret = _eglsnprintf(buf, len, "%s", p);
397
            if (ret > 0 && ret < len) {
398
               p = strrchr(buf, dir_sep);
399
               *p++ = ':';
400
 
401
               len -= p - buf;
402
               buf = p;
403
            }
404
         }
405
 
406
         /* append EGL_DRIVERS_PATH */
407
         p = getenv("EGL_DRIVERS_PATH");
408
         if (p) {
409
            ret = _eglsnprintf(buf, len, "%s:", p);
410
            if (ret > 0 && ret < len) {
411
               buf += ret;
412
               len -= ret;
413
            }
414
         }
415
      }
416
      else {
417
         _eglLog(_EGL_DEBUG,
418
               "ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
419
      }
420
 
421
      ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR);
422
      if (ret < 0 || ret >= len)
423
         search_path[0] = '\0';
424
 
425
      _eglLog(_EGL_DEBUG, "EGL search path is %s", search_path);
426
   }
427
#endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
428
 
429
   return search_path;
430
}
431
 
432
 
433
/**
434
 * Add the user driver to the module array.
435
 *
436
 * The user driver is specified by EGL_DRIVER.
437
 */
438
static EGLBoolean
439
_eglAddUserDriver(void)
440
{
441
   const char *search_path = _eglGetSearchPath();
442
   char *env;
443
   size_t name_len = 0;
444
 
445
   env = getenv("EGL_DRIVER");
446
#if defined(_EGL_OS_UNIX)
447
   if (env && strchr(env, '/')) {
448
      search_path = "";
449
      if ((geteuid() != getuid() || getegid() != getgid())) {
450
         _eglLog(_EGL_DEBUG,
451
               "ignore EGL_DRIVER for setuid/setgid binaries");
452
         env = NULL;
453
      }
454
   }
455
   else if (env) {
456
      char *suffix = strchr(env, '.');
457
      name_len = (suffix) ? suffix - env : strlen(env);
458
   }
459
#else
460
   if (env)
461
      name_len = strlen(env);
462
#endif /* _EGL_OS_UNIX */
463
 
464
   /*
465
    * Try built-in drivers first if we know the driver name.  This makes sure
466
    * we do not load the outdated external driver that is still on the
467
    * filesystem.
468
    */
469
   if (name_len) {
470
      _EGLModule *mod;
471
      EGLint i;
472
 
473
      for (i = 0; _eglBuiltInDrivers[i].name; i++) {
474
         if (strlen(_eglBuiltInDrivers[i].name) == name_len &&
475
             !strncmp(_eglBuiltInDrivers[i].name, env, name_len)) {
476
            mod = _eglAddModule(env);
477
            if (mod)
478
               mod->BuiltIn = _eglBuiltInDrivers[i].main;
479
 
480
            return EGL_TRUE;
481
         }
482
      }
483
   }
484
 
485
   /* otherwise, treat env as a path */
486
   if (env) {
487
      _eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
488
 
489
      return EGL_TRUE;
490
   }
491
 
492
   return EGL_FALSE;
493
}
494
 
495
 
496
/**
497
 * Add egl_gallium to the module array.
498
 */
499
static void
500
_eglAddGalliumDriver(void)
501
{
502
#ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
503
   void *external = (void *) "egl_gallium";
504
   _eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external);
505
#endif
506
}
507
#endif
508
 
509
 
510
/**
511
 * Add built-in drivers to the module array.
512
 */
513
static void
514
_eglAddBuiltInDrivers(void)
515
{
516
   _EGLModule *mod;
517
   EGLint i;
518
 
519
   for (i = 0; _eglBuiltInDrivers[i].name; i++) {
520
      mod = _eglAddModule(_eglBuiltInDrivers[i].name);
521
      if (mod)
522
         mod->BuiltIn = _eglBuiltInDrivers[i].main;
523
   }
524
}
525
 
526
 
527
/**
528
 * Add drivers to the module array.  Drivers will be loaded as they are matched
529
 * to displays.
530
 */
531
static EGLBoolean
532
_eglAddDrivers(void)
533
{
534
   if (_eglModules)
535
      return EGL_TRUE;
536
 
537
//   if (!_eglAddUserDriver()) {
538
      /*
539
       * Add other drivers only when EGL_DRIVER is not set.  The order here
540
       * decides the priorities.
541
       */
542
//      _eglAddGalliumDriver();
543
      _eglAddBuiltInDrivers();
544
//   }
545
 
546
   return (_eglModules != NULL);
547
}
548
 
549
 
550
/**
551
 * A helper function for _eglMatchDriver.  It finds the first driver that can
552
 * initialize the display and return.
553
 */
554
static _EGLDriver *
555
_eglMatchAndInitialize(_EGLDisplay *dpy)
556
{
557
   _EGLDriver *drv = NULL;
558
   EGLint i = 0;
559
 
560
   if (!_eglAddDrivers()) {
561
      _eglLog(_EGL_WARNING, "failed to find any driver");
562
      return NULL;
563
   }
564
 
565
   if (dpy->Driver) {
566
      drv = dpy->Driver;
567
      /* no re-matching? */
568
      if (!drv->API.Initialize(drv, dpy))
569
         drv = NULL;
570
      return drv;
571
   }
572
 
573
   while (i < _eglModules->Size) {
574
      _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
575
 
576
      if (!_eglLoadModule(mod)) {
577
         /* remove invalid modules */
578
         _eglEraseArray(_eglModules, i, _eglFreeModule);
579
         continue;
580
      }
581
 
582
      if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
583
         drv = mod->Driver;
584
         break;
585
      }
586
      else {
587
         i++;
588
      }
589
   }
590
 
591
   return drv;
592
}
593
 
594
 
595
/**
596
 * Match a display to a driver.  The display is initialized unless test_only is
597
 * true.  The matching is done by finding the first driver that can initialize
598
 * the display.
599
 */
600
_EGLDriver *
601
_eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
602
{
603
   _EGLDriver *best_drv;
604
 
605
   assert(!dpy->Initialized);
606
 
607
   _eglLockMutex(&_eglModuleMutex);
608
 
609
   /* set options */
610
   dpy->Options.TestOnly = test_only;
611
   dpy->Options.UseFallback = EGL_FALSE;
612
 
613
   best_drv = _eglMatchAndInitialize(dpy);
614
   if (!best_drv) {
615
      dpy->Options.UseFallback = EGL_TRUE;
616
      best_drv = _eglMatchAndInitialize(dpy);
617
   }
618
 
619
   _eglUnlockMutex(&_eglModuleMutex);
620
 
621
   if (best_drv) {
622
      _eglLog(_EGL_DEBUG, "the best driver is %s%s",
623
            best_drv->Name, (test_only) ? " (test only) " : "");
624
      if (!test_only) {
625
         dpy->Driver = best_drv;
626
         dpy->Initialized = EGL_TRUE;
627
      }
628
   }
629
 
630
   return best_drv;
631
}
632
 
633
 
634
__eglMustCastToProperFunctionPointerType
635
_eglGetDriverProc(const char *procname)
636
{
637
   EGLint i;
638
   _EGLProc proc = NULL;
639
 
640
   if (!_eglModules) {
641
      /* load the driver for the default display */
642
      EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
643
      _EGLDisplay *dpy = _eglLookupDisplay(egldpy);
644
      if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
645
         return NULL;
646
   }
647
 
648
   for (i = 0; i < _eglModules->Size; i++) {
649
      _EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
650
 
651
      if (!mod->Driver)
652
         break;
653
      proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
654
      if (proc)
655
         break;
656
   }
657
 
658
   return proc;
659
}
660
 
661
 
662
/**
663
 * Unload all drivers.
664
 */
665
void
666
_eglUnloadDrivers(void)
667
{
668
   /* this is called at atexit time */
669
   if (_eglModules) {
670
      _eglDestroyArray(_eglModules, _eglFreeModule);
671
      _eglModules = NULL;
672
   }
673
}
674
 
675
#if 0
676
/**
677
 * Invoke a callback function on each EGL search path.
678
 *
679
 * The first argument of the callback function is the name of the search path.
680
 * The second argument is the length of the name.
681
 */
682
void
683
_eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
684
                      void *callback_data)
685
{
686
   const char *search_path = _eglGetSearchPath();
687
   _eglPreloadForEach(search_path, callback, callback_data);
688
}
689
#endif