Hi,

This patch series introduces two features to EGL core and fixes some
conformance issues.  The first feature is support for built-in driver.
The other one is to allow driver to install a customized logger for
_eglLog().

The first patch adds built-in driver support.  It is adapted from
WINDOWS_STATIC_LINK, with better error reporting and integrate better
with current driver model.  It is a matter of changing the Makefile to
build a libEGL.so with the driver built-in.

The second patch removes core EGL functions from eglGetProcAddress, as
required by the spec.

The third patch tries to fix an issue that eglGetProcAddress is called
really early (before any EGLDisplay is created).  The best shot is to
try to preload a driver, and get proc address from the preloaded driver.

The fourth patch allows any client api to be bound.  This simplifies the
code a bit, and it makes more sense.  Config attribute
EGL_RENDERABLE_TYPE is supposed to be used to choose a config that
support certain apis.  The apis supported by a display can also be
queried through EGL_CLIENT_APIS.

The last patch allows the log level and the logger to be changed by a
driver.  This is helpful on systems with an alternative logging
facility.

-- 
Regards,
olv
>From d4143491bee0398a7e69a6a9effd090e1b1708ad Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 28 Sep 2009 17:25:48 +0800
Subject: [PATCH 1/5] egl: Add support for driver built-in.

This allows an EGL driver to be compiled together with libEGL.so.  It
eliminates the need to specify a driver, or support module loading on
new platforms.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/egldriver.c |  157 +++++++++++++++++++++++++++-------------------
 src/egl/main/egllog.c    |    4 -
 2 files changed, 93 insertions(+), 68 deletions(-)

diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c
index 87786e3..0c76c79 100644
--- a/src/egl/main/egldriver.c
+++ b/src/egl/main/egldriver.c
@@ -22,59 +22,70 @@
 
 #if defined(_EGL_PLATFORM_X)
 #include <dlfcn.h>
-#elif defined(_EGL_PLATFORM_WINDOWS)
-/* Use static linking on Windows for now */
-#define WINDOWS_STATIC_LINK
 #endif
 
+
 /**
  * Wrappers for dlopen/dlclose()
  */
 #if defined(_EGL_PLATFORM_WINDOWS)
-#ifdef WINDOWS_STATIC_LINK
-   static const char *DefaultDriverName = "Windows EGL Static Library";
-#else
-   /* XXX Need to decide how to do dynamic name lookup on Windows */
-   static const char *DefaultDriverName = "TBD";
-#endif
-   typedef HMODULE lib_handle;
-
-   static HMODULE
-   open_library(const char *filename)
-   {
-#ifdef WINDOWS_STATIC_LINK
-      return 0;
-#else
-      return LoadLibrary(filename);
-#endif
-   }
 
-   static void
-   close_library(HMODULE lib)
-   {
-#ifdef WINDOWS_STATIC_LINK
-#else
-      FreeLibrary(lib);
-#endif
-   }
+
+/* XXX Need to decide how to do dynamic name lookup on Windows */
+static const char DefaultDriverName[] = "TBD";
+
+typedef HMODULE lib_handle;
+
+static HMODULE
+open_library(const char *filename)
+{
+   return LoadLibrary(filename);
+}
+
+static void
+close_library(HMODULE lib)
+{
+   FreeLibrary(lib);
+}
+
 
 #elif defined(_EGL_PLATFORM_X)
-   static const char *DefaultDriverName = "egl_softpipe";
 
-   typedef void * lib_handle;
 
-   static void *
-   open_library(const char *filename)
-   {
-      return dlopen(filename, RTLD_LAZY);
-   }
+static const char DefaultDriverName[] = "egl_softpipe";
+
+typedef void * lib_handle;
+
+static void *
+open_library(const char *filename)
+{
+   return dlopen(filename, RTLD_LAZY);
+}
+
+static void
+close_library(void *lib)
+{
+   dlclose(lib);
+}
+
+#else /* _EGL_PLATFORM_NO_OS */
+
+static const char DefaultDriverName[] = "builtin";
+
+typedef void *lib_handle;
+
+static INLINE void *
+open_library(const char *filename)
+{
+   return (void *) filename;
+}
+
+static INLINE void
+close_library(void *lib)
+{
+}
+
 
-   static void
-   close_library(void *lib)
-   {
-      dlclose(lib);
-   }
-   
 #endif
 
 
@@ -95,14 +106,22 @@ _eglChooseDriver(_EGLDisplay *dpy, char **argsRet)
       path = _eglstrdup(path);
 
 #if defined(_EGL_PLATFORM_X)
-   if (!path && dpy->NativeDisplay) {
+   if (!path && dpy && dpy->NativeDisplay) {
       /* assume (wrongly!) that the native display is a display string */
       path = _eglSplitDisplayString((const char *) dpy->NativeDisplay, &args);
    }
    suffix = "so";
 #elif defined(_EGL_PLATFORM_WINDOWS)
    suffix = "dll";
-#endif /* _EGL_PLATFORM_X */
+#else /* _EGL_PLATFORM_NO_OS */
+   if (path) {
+      /* force the use of the default driver */
+      _eglLog(_EGL_DEBUG, "ignore EGL_DRIVER");
+      free(path);
+      path = NULL;
+   }
+   suffix = NULL;
+#endif
 
    if (!path)
       path = _eglstrdup(DefaultDriverName);
@@ -136,43 +155,48 @@ _eglChooseDriver(_EGLDisplay *dpy, char **argsRet)
 static _EGLMain_t
 _eglOpenLibrary(const char *driverPath, lib_handle *handle)
 {
-   _EGLMain_t mainFunc;
    lib_handle lib;
+   _EGLMain_t mainFunc = NULL;
+   const char *error = "unknown error";
 
    assert(driverPath);
 
-#if defined(_EGL_PLATFORM_WINDOWS)
-/* Use static linking on Windows for now */
-#ifdef WINDOWS_STATIC_LINK
-   lib = 0;
-   mainFunc = (_EGLMain_t)_eglMain;
-#else
-   /* XXX untested */
    _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
    lib = open_library(driverPath);
-   if (!lib) {
-      _eglLog(_EGL_WARNING, "Could not open %s",
-              driverPath);
-      return NULL;
+
+#if defined(_EGL_PLATFORM_WINDOWS)
+   /* XXX untested */
+   if (lib)
+      mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
+#elif defined(_EGL_PLATFORM_X)
+   if (lib) {
+      mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
+      if (!mainFunc)
+         error = dlerror();
+   }
+   else {
+      error = dlerror();
    }
-   mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
+#else /* _EGL_PLATFORM_NO_OS */
+   /* must be the default driver name */
+   if (strcmp(driverPath, DefaultDriverName) == 0)
+      mainFunc = (_EGLMain_t) _eglMain;
+   else
+      error = "not builtin driver";
 #endif
-#elif defined(_EGL_PLATFORM_X)
-   _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
-   lib = open_library(driverPath);
+
    if (!lib) {
-      _eglLog(_EGL_WARNING, "Could not open %s (%s)",
-              driverPath, dlerror());
+      _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
+              driverPath, error);
       if (!getenv("EGL_DRIVER"))
          _eglLog(_EGL_WARNING,
                  "The driver can be overridden by setting EGL_DRIVER");
       return NULL;
    }
-   mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
-#endif
 
    if (!mainFunc) {
-      _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverPath);
+      _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
+              driverPath, error);
       if (lib)
          close_library(lib);
       return NULL;
@@ -428,6 +452,11 @@ _eglFindAPIs(void)
    const char *es2_libname = "libGLESv2.so";
    const char *gl_libname = "libGL.so";
    const char *vg_libname = "libOpenVG.so";
+#else /* _EGL_PLATFORM_NO_OS */
+   const char *es1_libname = NULL;
+   const char *es2_libname = NULL;
+   const char *gl_libname = NULL;
+   const char *vg_libname = NULL;
 #endif
 
    if ((lib = open_library(es1_libname))) {
diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c
index 1d7a0a3..23eb523 100644
--- a/src/egl/main/egllog.c
+++ b/src/egl/main/egllog.c
@@ -21,11 +21,7 @@ static EGLint ReportingLevel = -1;
 static void
 log_level_initialize(void)
 {
-#if defined(_EGL_PLATFORM_X)  
    char *log_env = getenv("EGL_LOG_LEVEL");
-#else
-   char *log_env = NULL;
-#endif
 
    if (log_env == NULL) {
       ReportingLevel = FALLBACK_LOG_LEVEL;
-- 
1.6.3.3

>From f6069d37f89727304538c1b56e93d8897450b713 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Sat, 15 Aug 2009 22:44:46 +0800
Subject: [PATCH 2/5] egl: Remove core functions from eglGetProcAddress.

eglGetProcAddress may not be used to query core (non-extension)
functions.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglapi.c |   61 +++++++++++++------------------------------------
 1 files changed, 16 insertions(+), 45 deletions(-)

diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 29617b7..82ee9d9 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -586,43 +586,11 @@ eglGetError(void)
 
 void (* EGLAPIENTRY eglGetProcAddress(const char *procname))()
 {
-   typedef void (*genericFunc)();
-   struct name_function {
+   static const struct {
       const char *name;
       _EGLProc function;
-   };
-   static struct name_function egl_functions[] = {
-      /* alphabetical order */
-      { "eglBindTexImage", (_EGLProc) eglBindTexImage },
-      { "eglChooseConfig", (_EGLProc) eglChooseConfig },
-      { "eglCopyBuffers", (_EGLProc) eglCopyBuffers },
-      { "eglCreateContext", (_EGLProc) eglCreateContext },
-      { "eglCreatePbufferSurface", (_EGLProc) eglCreatePbufferSurface },
-      { "eglCreatePixmapSurface", (_EGLProc) eglCreatePixmapSurface },
-      { "eglCreateWindowSurface", (_EGLProc) eglCreateWindowSurface },
-      { "eglDestroyContext", (_EGLProc) eglDestroyContext },
-      { "eglDestroySurface", (_EGLProc) eglDestroySurface },
-      { "eglGetConfigAttrib", (_EGLProc) eglGetConfigAttrib },
-      { "eglGetConfigs", (_EGLProc) eglGetConfigs },
-      { "eglGetCurrentContext", (_EGLProc) eglGetCurrentContext },
-      { "eglGetCurrentDisplay", (_EGLProc) eglGetCurrentDisplay },
-      { "eglGetCurrentSurface", (_EGLProc) eglGetCurrentSurface },
-      { "eglGetDisplay", (_EGLProc) eglGetDisplay },
-      { "eglGetError", (_EGLProc) eglGetError },
-      { "eglGetProcAddress", (_EGLProc) eglGetProcAddress },
-      { "eglInitialize", (_EGLProc) eglInitialize },
-      { "eglMakeCurrent", (_EGLProc) eglMakeCurrent },
-      { "eglQueryContext", (_EGLProc) eglQueryContext },
-      { "eglQueryString", (_EGLProc) eglQueryString },
-      { "eglQuerySurface", (_EGLProc) eglQuerySurface },
-      { "eglReleaseTexImage", (_EGLProc) eglReleaseTexImage },
-      { "eglSurfaceAttrib", (_EGLProc) eglSurfaceAttrib },
-      { "eglSwapBuffers", (_EGLProc) eglSwapBuffers },
-      { "eglSwapInterval", (_EGLProc) eglSwapInterval },
-      { "eglTerminate", (_EGLProc) eglTerminate },
-      { "eglWaitGL", (_EGLProc) eglWaitGL },
-      { "eglWaitNative", (_EGLProc) eglWaitNative },
-      /* Extensions */
+   } egl_functions[] = {
+      /* extensions only */
 #ifdef EGL_MESA_screen_surface
       { "eglChooseModeMESA", (_EGLProc) eglChooseModeMESA },
       { "eglGetModesMESA", (_EGLProc) eglGetModesMESA },
@@ -637,19 +605,16 @@ void (* EGLAPIENTRY eglGetProcAddress(const char *procname))()
       { "eglQueryScreenModeMESA", (_EGLProc) eglQueryScreenModeMESA },
       { "eglQueryModeStringMESA", (_EGLProc) eglQueryModeStringMESA },
 #endif /* EGL_MESA_screen_surface */
-#ifdef EGL_VERSION_1_2
-      { "eglBindAPI", (_EGLProc) eglBindAPI },
-      { "eglCreatePbufferFromClientBuffer", (_EGLProc) eglCreatePbufferFromClientBuffer },
-      { "eglQueryAPI", (_EGLProc) eglQueryAPI },
-      { "eglReleaseThread", (_EGLProc) eglReleaseThread },
-      { "eglWaitClient", (_EGLProc) eglWaitClient },
-#endif /* EGL_VERSION_1_2 */
       { NULL, NULL }
    };
    EGLint i;
-   for (i = 0; egl_functions[i].name; i++) {
-      if (strcmp(egl_functions[i].name, procname) == 0) {
-         return (genericFunc) egl_functions[i].function;
+
+   if (!procname)
+      return NULL;
+   if (strncmp(procname, "egl", 3) == 0) {
+      for (i = 0; egl_functions[i].name; i++) {
+         if (strcmp(egl_functions[i].name, procname) == 0)
+            return egl_functions[i].function;
       }
    }
 
@@ -664,6 +629,9 @@ void (* EGLAPIENTRY eglGetProcAddress(const char *procname))()
 }
 
 
+#ifdef EGL_MESA_screen_surface
+
+
 /*
  * EGL_MESA_screen extension
  */
@@ -838,6 +806,9 @@ eglQueryModeStringMESA(EGLDisplay dpy, EGLModeMESA mode)
 }
 
 
+#endif /* EGL_MESA_screen_surface */
+
+
 /**
  ** EGL 1.2
  **/
-- 
1.6.3.3

>From 994cb001231530eea171a536c572814dc94ebcd3 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 28 Sep 2009 17:39:07 +0800
Subject: [PATCH 3/5] egl: Preload a driver if eglGetProcAddress is called early.


Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglapi.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 82ee9d9..23d841d 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -618,6 +618,10 @@ void (* EGLAPIENTRY eglGetProcAddress(const char *procname))()
       }
    }
 
+   /* preload a driver if there isn't one */
+   if (!_eglGlobal.NumDrivers)
+      _eglPreloadDriver(NULL);
+
    /* now loop over drivers to query their procs */
    for (i = 0; i < _eglGlobal.NumDrivers; i++) {
       _EGLProc p = _eglGlobal.Drivers[i]->API.GetProcAddress(procname);
-- 
1.6.3.3

>From cb34419fcb769b3a58d9ed6b83819262c4c358ff Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 17 Aug 2009 15:53:54 +0800
Subject: [PATCH 4/5] egl: Allow binding to any client API.

As a result, EGL_NONE is no longer a valid client API.  And it is
possible that no config supports the current bound API.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglapi.c     |   32 +++-----------------------------
 src/egl/main/eglcurrent.c |    2 +-
 src/egl/main/eglcurrent.h |   23 +++++++++++++++--------
 src/egl/main/eglglobals.c |    1 -
 src/egl/main/eglglobals.h |    3 ---
 5 files changed, 19 insertions(+), 42 deletions(-)

diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 23d841d..d86ef9c 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -92,8 +92,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
       snprintf(disp->Version, sizeof(disp->Version),
                "%d.%d (%s)", major_int, minor_int, drv->Name);
 
-      /* update the global notion of supported APIs */
-      _eglGlobal.ClientAPIsMask |= disp->ClientAPIsMask;
+      /* limit to APIs supported by core */
+      disp->ClientAPIsMask &= _EGL_API_ALL_BITS;
 
       disp->Driver = drv;
    } else {
@@ -842,33 +842,7 @@ eglBindAPI(EGLenum api)
    if (!_eglIsApiValid(api))
       return _eglError(EGL_BAD_PARAMETER, "eglBindAPI");
 
-   switch (api) {
-#ifdef EGL_VERSION_1_4
-   case EGL_OPENGL_API:
-      if (_eglGlobal.ClientAPIsMask & EGL_OPENGL_BIT) {
-         t->CurrentAPIIndex = _eglConvertApiToIndex(api);
-         return EGL_TRUE;
-      }
-      _eglError(EGL_BAD_PARAMETER, "eglBindAPI");
-      return EGL_FALSE;
-#endif
-   case EGL_OPENGL_ES_API:
-      if (_eglGlobal.ClientAPIsMask & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT)) {
-         t->CurrentAPIIndex = _eglConvertApiToIndex(api);
-         return EGL_TRUE;
-      }
-      _eglError(EGL_BAD_PARAMETER, "eglBindAPI");
-      return EGL_FALSE;
-   case EGL_OPENVG_API:
-      if (_eglGlobal.ClientAPIsMask & EGL_OPENVG_BIT) {
-         t->CurrentAPIIndex = _eglConvertApiToIndex(api);
-         return EGL_TRUE;
-      }
-      _eglError(EGL_BAD_PARAMETER, "eglBindAPI");
-      return EGL_FALSE;
-   default:
-      return EGL_FALSE;
-   }
+   t->CurrentAPIIndex = _eglConvertApiToIndex(api);
    return EGL_TRUE;
 }
 
diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c
index 4431f96..ca7a077 100644
--- a/src/egl/main/eglcurrent.c
+++ b/src/egl/main/eglcurrent.c
@@ -9,7 +9,7 @@
 
 /* This should be kept in sync with _eglInitThreadInfo() */
 #define _EGL_THREAD_INFO_INITIALIZER \
-   { EGL_SUCCESS, { NULL }, 1 }
+   { EGL_SUCCESS, { NULL }, 0 }
 
 /* a fallback thread info to guarantee that every thread always has one */
 static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h
index 8eb2410..9503e0a 100644
--- a/src/egl/main/eglcurrent.h
+++ b/src/egl/main/eglcurrent.h
@@ -4,8 +4,16 @@
 #include "egltypedefs.h"
 
 
-#define _EGL_API_NUM_INDICES \
-   (EGL_OPENGL_API - EGL_OPENGL_ES_API + 2) /* idx 0 is for EGL_NONE */
+#define _EGL_API_ALL_BITS \
+   (EGL_OPENGL_ES_BIT   | \
+    EGL_OPENVG_BIT      | \
+    EGL_OPENGL_ES2_BIT  | \
+    EGL_OPENGL_BIT)
+
+
+#define _EGL_API_FIRST_API EGL_OPENGL_ES_API
+#define _EGL_API_LAST_API EGL_OPENGL_API
+#define _EGL_API_NUM_APIS (_EGL_API_LAST_API - _EGL_API_FIRST_API + 1)
 
 
 /**
@@ -14,20 +22,19 @@
 struct _egl_thread_info
 {
    EGLint LastError;
-   _EGLContext *CurrentContexts[_EGL_API_NUM_INDICES];
+   _EGLContext *CurrentContexts[_EGL_API_NUM_APIS];
    /* use index for fast access to current context */
    EGLint CurrentAPIIndex;
 };
 
 
 /**
- * Return true if a client API enum can be converted to an index.
+ * Return true if a client API enum is recognized.
  */
 static INLINE EGLBoolean
 _eglIsApiValid(EGLenum api)
 {
-   return ((api >= EGL_OPENGL_ES_API && api <= EGL_OPENGL_API) ||
-           api == EGL_NONE);
+   return (api >= _EGL_API_FIRST_API && api <= _EGL_API_LAST_API);
 }
 
 
@@ -38,7 +45,7 @@ _eglIsApiValid(EGLenum api)
 static INLINE EGLint
 _eglConvertApiToIndex(EGLenum api)
 {
-   return (api != EGL_NONE) ? api - EGL_OPENGL_ES_API + 1 : 0;
+   return api - _EGL_API_FIRST_API;
 }
 
 
@@ -49,7 +56,7 @@ _eglConvertApiToIndex(EGLenum api)
 static INLINE EGLenum
 _eglConvertApiFromIndex(EGLint idx)
 {
-   return (idx) ? EGL_OPENGL_ES_API + idx - 1 : EGL_NONE;
+   return _EGL_API_FIRST_API + idx;
 }
 
 
diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c
index 3ae4c1a..30d9fe9 100644
--- a/src/egl/main/eglglobals.c
+++ b/src/egl/main/eglglobals.c
@@ -15,7 +15,6 @@ struct _egl_global _eglGlobal =
    &_eglGlobalMutex,       /* Mutex */
    NULL,                   /* DisplayList */
    1,                      /* FreeScreenHandle */
-   0x0,                    /* ClientAPIsMask */
    0,                      /* NumDrivers */
    { NULL },               /* Drivers */
    2,                      /* NumAtExitCalls */
diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h
index 5851107..5ebb914 100644
--- a/src/egl/main/eglglobals.h
+++ b/src/egl/main/eglglobals.h
@@ -19,9 +19,6 @@ struct _egl_global
 
    EGLScreenMESA FreeScreenHandle;
 
-   /* bitmaks of supported APIs (supported by _some_ driver) */
-   EGLint ClientAPIsMask;
-
    EGLint NumDrivers;
    _EGLDriver *Drivers[10];
 
-- 
1.6.3.3

>From 92219c85d02de2b3d38d65799fad5bc404c997ff Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Tue, 29 Sep 2009 16:11:06 +0800
Subject: [PATCH 5/5] egl: Improve logging facility.

Add _eglSetLogger and _eglSetLogLevel to allow drivers to change the
message logger or report level.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglglobals.c |    7 +-
 src/egl/main/egllog.c     |  181 ++++++++++++++++++++++++++++++++-------------
 src/egl/main/egllog.h     |   11 +++
 3 files changed, 145 insertions(+), 54 deletions(-)

diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c
index 30d9fe9..443d0f0 100644
--- a/src/egl/main/eglglobals.c
+++ b/src/egl/main/eglglobals.c
@@ -18,9 +18,10 @@ struct _egl_global _eglGlobal =
    0,                      /* NumDrivers */
    { NULL },               /* Drivers */
    2,                      /* NumAtExitCalls */
-   {                       /* AtExitCalls */
-      _eglFiniDisplay,
-      _eglUnloadDrivers
+   {
+      /* default AtExitCalls, called in reverse order */
+      _eglUnloadDrivers, /* always called last */
+      _eglFiniDisplay
    },
 };
 
diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c
index 23eb523..11a9bf7 100644
--- a/src/egl/main/egllog.c
+++ b/src/egl/main/egllog.c
@@ -9,47 +9,140 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #include "egllog.h"
+#include "eglmutex.h"
 
 #define MAXSTRING 1000
-#define FALLBACK_LOG_LEVEL      _EGL_WARNING
-#define FALLBACK_LOG_LEVEL_STR  "warning"
+#define FALLBACK_LOG_LEVEL _EGL_WARNING
 
-static EGLint ReportingLevel = -1;
 
+static struct {
+   _EGLMutex mutex;
 
-static void
-log_level_initialize(void)
+   EGLBoolean initialized;
+   EGLint level;
+   _EGLLogProc logger;
+   EGLint num_messages;
+} logging = {
+   _EGL_MUTEX_INITIALIZER,
+   EGL_FALSE,
+   FALLBACK_LOG_LEVEL,
+   NULL,
+   0
+};
+
+static const char *level_strings[] = {
+   /* the order is important */
+   "fatal",
+   "warning",
+   "info",
+   "debug",
+   NULL
+};
+
+
+/**
+ * Set the function to be called when there is a message to log.
+ * Note that the function will be called with an internal lock held.
+ * Recursive logging is not allowed.
+ */
+void
+_eglSetLogProc(_EGLLogProc logger)
 {
-   char *log_env = getenv("EGL_LOG_LEVEL");
+   EGLint num_messages = 0;
 
-   if (log_env == NULL) {
-      ReportingLevel = FALLBACK_LOG_LEVEL;
-   }
-   else if (strcasecmp(log_env, "fatal") == 0) {
-      ReportingLevel = _EGL_FATAL;
-   }
-   else if (strcasecmp(log_env, "warning") == 0) {
-      ReportingLevel = _EGL_WARNING;
+   _eglLockMutex(&logging.mutex);
+
+   if (logging.logger != logger) {
+      logging.logger = logger;
+
+      num_messages = logging.num_messages;
+      logging.num_messages = 0;
    }
-   else if (strcasecmp(log_env, "info") == 0) {
-      ReportingLevel = _EGL_INFO;
+
+   _eglUnlockMutex(&logging.mutex);
+
+   if (num_messages)
+      _eglLog(_EGL_DEBUG,
+              "New logger installed. "
+              "Messages before the new logger might not be available.");
+}
+
+
+/**
+ * Set the log reporting level.
+ */
+void
+_eglSetLogLevel(EGLint level)
+{
+   switch (level) {
+   case _EGL_FATAL:
+   case _EGL_WARNING:
+   case _EGL_INFO:
+   case _EGL_DEBUG:
+      _eglLockMutex(&logging.mutex);
+      logging.level = level;
+      _eglUnlockMutex(&logging.mutex);
+      break;
+   default:
+      break;
    }
-   else if (strcasecmp(log_env, "debug") == 0) {
-      ReportingLevel = _EGL_DEBUG;
+}
+
+
+/**
+ * The default logger.  It prints the message to stderr.
+ */
+static void
+_eglDefaultLogger(EGLint level, const char *msg)
+{
+   fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
+}
+
+
+/**
+ * Initialize the logging facility.
+ */
+static void
+_eglInitLogger(void)
+{
+   const char *log_env;
+   EGLint i, level = -1;
+
+   if (logging.initialized)
+      return;
+
+   log_env = getenv("EGL_LOG_LEVEL");
+   if (log_env) {
+      for (i = 0; level_strings[i]; i++) {
+         if (strcasecmp(log_env, level_strings[i]) == 0) {
+            level = i;
+            break;
+         }
+      }
    }
    else {
-      fprintf(stderr, "Unrecognized EGL_LOG_LEVEL environment variable value. "
+      level = FALLBACK_LOG_LEVEL;
+   }
+
+   logging.logger = _eglDefaultLogger;
+   logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
+   logging.initialized = EGL_TRUE;
+
+   /* it is fine to call _eglLog now */
+   if (log_env && level < 0) {
+      _eglLog(_EGL_WARNING,
+              "Unrecognized EGL_LOG_LEVEL environment variable value. "
               "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
-              "Got \"%s\". Falling back to \"%s\".\n",
-              log_env, FALLBACK_LOG_LEVEL_STR);
-      ReportingLevel = FALLBACK_LOG_LEVEL;
+              "Got \"%s\". Falling back to \"%s\".",
+              log_env, level_strings[FALLBACK_LOG_LEVEL]);
    }
 }
 
 
 /**
- * Log a message to stderr.
+ * Log a message with message logger.
  * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
  */
 void
@@ -57,40 +150,26 @@ _eglLog(EGLint level, const char *fmtStr, ...)
 {
    va_list args;
    char msg[MAXSTRING];
-   const char *levelStr;
-   static int log_level_initialized = 0;
 
-   if (!log_level_initialized) {
-      log_level_initialize();
-      log_level_initialized = 1;
-   }
+   /* one-time initialization; a little race here is fine */
+   if (!logging.initialized)
+      _eglInitLogger();
+   if (level > logging.level || level < 0)
+      return;
 
-   if (level <= ReportingLevel) {
-      switch (level) {
-      case _EGL_FATAL:
-         levelStr = "Fatal";
-         break;
-      case _EGL_WARNING:
-         levelStr = "Warning";
-         break;
-      case _EGL_INFO:
-         levelStr = "Info";
-         break;
-      case _EGL_DEBUG:
-         levelStr = "Debug";
-         break;
-      default:
-         levelStr = "";
-      }
+   _eglLockMutex(&logging.mutex);
 
+   if (logging.logger) {
       va_start(args, fmtStr);
       vsnprintf(msg, MAXSTRING, fmtStr, args);
       va_end(args);
 
-      fprintf(stderr, "libEGL %s: %s\n", levelStr, msg);
-
-      if (level == _EGL_FATAL) {
-         exit(1); /* or abort()? */
-      }
+      logging.logger(level, msg);
+      logging.num_messages++;
    }
+
+   _eglUnlockMutex(&logging.mutex);
+
+   if (level == _EGL_FATAL)
+      exit(1); /* or abort()? */
 }
diff --git a/src/egl/main/egllog.h b/src/egl/main/egllog.h
index 2fa352f..83c8bb7 100644
--- a/src/egl/main/egllog.h
+++ b/src/egl/main/egllog.h
@@ -9,6 +9,17 @@
 #define _EGL_DEBUG   3   /* useful info for debugging */
 
 
+typedef void (*_EGLLogProc)(EGLint level, const char *msg);
+
+
+extern void
+_eglSetLogProc(_EGLLogProc logger);
+
+
+extern void
+_eglSetLogLevel(EGLint level);
+
+
 extern void
 _eglLog(EGLint level, const char *fmtStr, ...);
 
-- 
1.6.3.3

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Mesa3d-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to