llvmpipe: twoside for specular color also
[mesa.git] / src / egl / main / egllog.c
1 /**
2 * Logging facility for debug/info messages.
3 * _EGL_FATAL messages are printed to stderr
4 * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs.
5 */
6
7
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "egllog.h"
14 #include "eglstring.h"
15 #include "eglmutex.h"
16
17 #define MAXSTRING 1000
18 #define FALLBACK_LOG_LEVEL _EGL_WARNING
19
20
21 static struct {
22 _EGLMutex mutex;
23
24 EGLBoolean initialized;
25 EGLint level;
26 _EGLLogProc logger;
27 EGLint num_messages;
28 } logging = {
29 _EGL_MUTEX_INITIALIZER,
30 EGL_FALSE,
31 FALLBACK_LOG_LEVEL,
32 NULL,
33 0
34 };
35
36 static const char *level_strings[] = {
37 /* the order is important */
38 "fatal",
39 "warning",
40 "info",
41 "debug",
42 NULL
43 };
44
45
46 /**
47 * Set the function to be called when there is a message to log.
48 * Note that the function will be called with an internal lock held.
49 * Recursive logging is not allowed.
50 */
51 void
52 _eglSetLogProc(_EGLLogProc logger)
53 {
54 EGLint num_messages = 0;
55
56 _eglLockMutex(&logging.mutex);
57
58 if (logging.logger != logger) {
59 logging.logger = logger;
60
61 num_messages = logging.num_messages;
62 logging.num_messages = 0;
63 }
64
65 _eglUnlockMutex(&logging.mutex);
66
67 if (num_messages)
68 _eglLog(_EGL_DEBUG,
69 "New logger installed. "
70 "Messages before the new logger might not be available.");
71 }
72
73
74 /**
75 * Set the log reporting level.
76 */
77 void
78 _eglSetLogLevel(EGLint level)
79 {
80 switch (level) {
81 case _EGL_FATAL:
82 case _EGL_WARNING:
83 case _EGL_INFO:
84 case _EGL_DEBUG:
85 _eglLockMutex(&logging.mutex);
86 logging.level = level;
87 _eglUnlockMutex(&logging.mutex);
88 break;
89 default:
90 break;
91 }
92 }
93
94
95 /**
96 * The default logger. It prints the message to stderr.
97 */
98 static void
99 _eglDefaultLogger(EGLint level, const char *msg)
100 {
101 fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
102 }
103
104
105 /**
106 * Initialize the logging facility.
107 */
108 static void
109 _eglInitLogger(void)
110 {
111 const char *log_env;
112 EGLint i, level = -1;
113
114 if (logging.initialized)
115 return;
116
117 log_env = getenv("EGL_LOG_LEVEL");
118 if (log_env) {
119 for (i = 0; level_strings[i]; i++) {
120 if (_eglstrcasecmp(log_env, level_strings[i]) == 0) {
121 level = i;
122 break;
123 }
124 }
125 }
126 else {
127 level = FALLBACK_LOG_LEVEL;
128 }
129
130 logging.logger = _eglDefaultLogger;
131 logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
132 logging.initialized = EGL_TRUE;
133
134 /* it is fine to call _eglLog now */
135 if (log_env && level < 0) {
136 _eglLog(_EGL_WARNING,
137 "Unrecognized EGL_LOG_LEVEL environment variable value. "
138 "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
139 "Got \"%s\". Falling back to \"%s\".",
140 log_env, level_strings[FALLBACK_LOG_LEVEL]);
141 }
142 }
143
144
145 /**
146 * Log a message with message logger.
147 * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
148 */
149 void
150 _eglLog(EGLint level, const char *fmtStr, ...)
151 {
152 va_list args;
153 char msg[MAXSTRING];
154
155 /* one-time initialization; a little race here is fine */
156 if (!logging.initialized)
157 _eglInitLogger();
158 if (level > logging.level || level < 0)
159 return;
160
161 _eglLockMutex(&logging.mutex);
162
163 if (logging.logger) {
164 va_start(args, fmtStr);
165 vsnprintf(msg, MAXSTRING, fmtStr, args);
166 va_end(args);
167
168 logging.logger(level, msg);
169 logging.num_messages++;
170 }
171
172 _eglUnlockMutex(&logging.mutex);
173
174 if (level == _EGL_FATAL)
175 exit(1); /* or abort()? */
176 }