Subversion Repositories Kolibri OS

Rev

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