mesa: move GL_ARB_debug_output code into new debug_output.c file
[mesa.git] / src / mesa / main / errors.c
1 /**
2 * \file errors.c
3 * Mesa debugging and error handling functions.
4 */
5
6 /*
7 * Mesa 3-D graphics library
8 *
9 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include "errors.h"
34 #include "enums.h"
35 #include "imports.h"
36 #include "context.h"
37 #include "debug_output.h"
38 #include "dispatch.h"
39 #include "hash.h"
40 #include "mtypes.h"
41 #include "version.h"
42 #include "util/hash_table.h"
43 #include "util/simple_list.h"
44
45
46 static FILE *LogFile = NULL;
47
48
49 static void
50 output_if_debug(const char *prefixString, const char *outputString,
51 GLboolean newline)
52 {
53 static int debug = -1;
54
55 /* Init the local 'debug' var once.
56 * Note: the _mesa_init_debug() function should have been called
57 * by now so MESA_DEBUG_FLAGS will be initialized.
58 */
59 if (debug == -1) {
60 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
61 * etc to the named file. Otherwise, output to stderr.
62 */
63 const char *logFile = getenv("MESA_LOG_FILE");
64 if (logFile)
65 LogFile = fopen(logFile, "w");
66 if (!LogFile)
67 LogFile = stderr;
68 #ifdef DEBUG
69 /* in debug builds, print messages unless MESA_DEBUG="silent" */
70 if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
71 debug = 0;
72 else
73 debug = 1;
74 #else
75 /* in release builds, be silent unless MESA_DEBUG is set */
76 debug = getenv("MESA_DEBUG") != NULL;
77 #endif
78 }
79
80 /* Now only print the string if we're required to do so. */
81 if (debug) {
82 if (prefixString)
83 fprintf(LogFile, "%s: %s", prefixString, outputString);
84 else
85 fprintf(LogFile, "%s", outputString);
86 if (newline)
87 fprintf(LogFile, "\n");
88 fflush(LogFile);
89
90 #if defined(_WIN32)
91 /* stderr from windows applications without console is not usually
92 * visible, so communicate with the debugger instead */
93 {
94 char buf[4096];
95 _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
96 OutputDebugStringA(buf);
97 }
98 #endif
99 }
100 }
101
102
103 /**
104 * Return the file handle to use for debug/logging. Defaults to stderr
105 * unless MESA_LOG_FILE is defined.
106 */
107 FILE *
108 _mesa_get_log_file(void)
109 {
110 assert(LogFile);
111 return LogFile;
112 }
113
114
115 /**
116 * When a new type of error is recorded, print a message describing
117 * previous errors which were accumulated.
118 */
119 static void
120 flush_delayed_errors( struct gl_context *ctx )
121 {
122 char s[MAX_DEBUG_MESSAGE_LENGTH];
123
124 if (ctx->ErrorDebugCount) {
125 _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
126 ctx->ErrorDebugCount,
127 _mesa_enum_to_string(ctx->ErrorValue));
128
129 output_if_debug("Mesa", s, GL_TRUE);
130
131 ctx->ErrorDebugCount = 0;
132 }
133 }
134
135
136 /**
137 * Report a warning (a recoverable error condition) to stderr if
138 * either DEBUG is defined or the MESA_DEBUG env var is set.
139 *
140 * \param ctx GL context.
141 * \param fmtString printf()-like format string.
142 */
143 void
144 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
145 {
146 char str[MAX_DEBUG_MESSAGE_LENGTH];
147 va_list args;
148 va_start( args, fmtString );
149 (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
150 va_end( args );
151
152 if (ctx)
153 flush_delayed_errors( ctx );
154
155 output_if_debug("Mesa warning", str, GL_TRUE);
156 }
157
158
159 /**
160 * Report an internal implementation problem.
161 * Prints the message to stderr via fprintf().
162 *
163 * \param ctx GL context.
164 * \param fmtString problem description string.
165 */
166 void
167 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
168 {
169 va_list args;
170 char str[MAX_DEBUG_MESSAGE_LENGTH];
171 static int numCalls = 0;
172
173 (void) ctx;
174
175 if (numCalls < 50) {
176 numCalls++;
177
178 va_start( args, fmtString );
179 _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
180 va_end( args );
181 fprintf(stderr, "Mesa %s implementation error: %s\n",
182 PACKAGE_VERSION, str);
183 fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
184 }
185 }
186
187
188 static GLboolean
189 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
190 {
191 static GLint debug = -1;
192
193 /* Check debug environment variable only once:
194 */
195 if (debug == -1) {
196 const char *debugEnv = getenv("MESA_DEBUG");
197
198 #ifdef DEBUG
199 if (debugEnv && strstr(debugEnv, "silent"))
200 debug = GL_FALSE;
201 else
202 debug = GL_TRUE;
203 #else
204 if (debugEnv)
205 debug = GL_TRUE;
206 else
207 debug = GL_FALSE;
208 #endif
209 }
210
211 if (debug) {
212 if (ctx->ErrorValue != error ||
213 ctx->ErrorDebugFmtString != fmtString) {
214 flush_delayed_errors( ctx );
215 ctx->ErrorDebugFmtString = fmtString;
216 ctx->ErrorDebugCount = 0;
217 return GL_TRUE;
218 }
219 ctx->ErrorDebugCount++;
220 }
221 return GL_FALSE;
222 }
223
224
225 void
226 _mesa_gl_vdebug(struct gl_context *ctx,
227 GLuint *id,
228 enum mesa_debug_source source,
229 enum mesa_debug_type type,
230 enum mesa_debug_severity severity,
231 const char *fmtString,
232 va_list args)
233 {
234 char s[MAX_DEBUG_MESSAGE_LENGTH];
235 int len;
236
237 _mesa_debug_get_id(id);
238
239 len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
240
241 _mesa_log_msg(ctx, source, type, *id, severity, len, s);
242 }
243
244
245 void
246 _mesa_gl_debug(struct gl_context *ctx,
247 GLuint *id,
248 enum mesa_debug_source source,
249 enum mesa_debug_type type,
250 enum mesa_debug_severity severity,
251 const char *fmtString, ...)
252 {
253 va_list args;
254 va_start(args, fmtString);
255 _mesa_gl_vdebug(ctx, id, source, type, severity, fmtString, args);
256 va_end(args);
257 }
258
259
260 /**
261 * Record an OpenGL state error. These usually occur when the user
262 * passes invalid parameters to a GL function.
263 *
264 * If debugging is enabled (either at compile-time via the DEBUG macro, or
265 * run-time via the MESA_DEBUG environment variable), report the error with
266 * _mesa_debug().
267 *
268 * \param ctx the GL context.
269 * \param error the error value.
270 * \param fmtString printf() style format string, followed by optional args
271 */
272 void
273 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
274 {
275 GLboolean do_output, do_log;
276 /* Ideally this would be set up by the caller, so that we had proper IDs
277 * per different message.
278 */
279 static GLuint error_msg_id = 0;
280
281 _mesa_debug_get_id(&error_msg_id);
282
283 do_output = should_output(ctx, error, fmtString);
284
285 mtx_lock(&ctx->DebugMutex);
286 if (ctx->Debug) {
287 do_log = _mesa_debug_is_message_enabled(ctx->Debug,
288 MESA_DEBUG_SOURCE_API,
289 MESA_DEBUG_TYPE_ERROR,
290 error_msg_id,
291 MESA_DEBUG_SEVERITY_HIGH);
292 }
293 else {
294 do_log = GL_FALSE;
295 }
296 mtx_unlock(&ctx->DebugMutex);
297
298 if (do_output || do_log) {
299 char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
300 int len;
301 va_list args;
302
303 va_start(args, fmtString);
304 len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
305 va_end(args);
306
307 if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
308 /* Too long error message. Whoever calls _mesa_error should use
309 * shorter strings.
310 */
311 assert(0);
312 return;
313 }
314
315 len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
316 _mesa_enum_to_string(error), s);
317 if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
318 /* Same as above. */
319 assert(0);
320 return;
321 }
322
323 /* Print the error to stderr if needed. */
324 if (do_output) {
325 output_if_debug("Mesa: User error", s2, GL_TRUE);
326 }
327
328 /* Log the error via ARB_debug_output if needed.*/
329 if (do_log) {
330 _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR,
331 error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2);
332 }
333 }
334
335 /* Set the GL context error state for glGetError. */
336 _mesa_record_error(ctx, error);
337 }
338
339 void
340 _mesa_error_no_memory(const char *caller)
341 {
342 GET_CURRENT_CONTEXT(ctx);
343 _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller);
344 }
345
346 /**
347 * Report debug information. Print error message to stderr via fprintf().
348 * No-op if DEBUG mode not enabled.
349 *
350 * \param ctx GL context.
351 * \param fmtString printf()-style format string, followed by optional args.
352 */
353 void
354 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
355 {
356 #ifdef DEBUG
357 char s[MAX_DEBUG_MESSAGE_LENGTH];
358 va_list args;
359 va_start(args, fmtString);
360 _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
361 va_end(args);
362 output_if_debug("Mesa", s, GL_FALSE);
363 #endif /* DEBUG */
364 (void) ctx;
365 (void) fmtString;
366 }
367
368
369 void
370 _mesa_log(const char *fmtString, ...)
371 {
372 char s[MAX_DEBUG_MESSAGE_LENGTH];
373 va_list args;
374 va_start(args, fmtString);
375 _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
376 va_end(args);
377 output_if_debug("", s, GL_FALSE);
378 }
379
380
381 /**
382 * Report debug information from the shader compiler via GL_ARB_debug_output.
383 *
384 * \param ctx GL context.
385 * \param type The namespace to which this message belongs.
386 * \param id The message ID within the given namespace.
387 * \param msg The message to output. Must be null-terminated.
388 */
389 void
390 _mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id,
391 const char *msg)
392 {
393 enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
394 enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
395 int len;
396
397 _mesa_debug_get_id(id);
398
399 len = strlen(msg);
400
401 /* Truncate the message if necessary. */
402 if (len >= MAX_DEBUG_MESSAGE_LENGTH)
403 len = MAX_DEBUG_MESSAGE_LENGTH - 1;
404
405 _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
406 }