3 * Mesa debugging and error handling functions.
7 * Mesa 3-D graphics library
9 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
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.
37 #include "debug_output.h"
40 static FILE *LogFile
= NULL
;
44 output_if_debug(const char *prefixString
, const char *outputString
,
47 static int debug
= -1;
49 /* Init the local 'debug' var once.
50 * Note: the _mesa_init_debug() function should have been called
51 * by now so MESA_DEBUG_FLAGS will be initialized.
54 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
55 * etc to the named file. Otherwise, output to stderr.
57 const char *logFile
= getenv("MESA_LOG_FILE");
59 LogFile
= fopen(logFile
, "w");
63 /* in debug builds, print messages unless MESA_DEBUG="silent" */
64 if (MESA_DEBUG_FLAGS
& DEBUG_SILENT
)
69 /* in release builds, be silent unless MESA_DEBUG is set */
70 debug
= getenv("MESA_DEBUG") != NULL
;
74 /* Now only print the string if we're required to do so. */
77 fprintf(LogFile
, "%s: %s", prefixString
, outputString
);
79 fprintf(LogFile
, "%s", outputString
);
81 fprintf(LogFile
, "\n");
85 /* stderr from windows applications without console is not usually
86 * visible, so communicate with the debugger instead */
90 snprintf(buf
, sizeof(buf
), "%s: %s%s", prefixString
, outputString
, newline
? "\n" : "");
92 snprintf(buf
, sizeof(buf
), "%s%s", outputString
, newline
? "\n" : "");
93 OutputDebugStringA(buf
);
101 * Return the file handle to use for debug/logging. Defaults to stderr
102 * unless MESA_LOG_FILE is defined.
105 _mesa_get_log_file(void)
113 * When a new type of error is recorded, print a message describing
114 * previous errors which were accumulated.
117 flush_delayed_errors( struct gl_context
*ctx
)
119 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
121 if (ctx
->ErrorDebugCount
) {
122 snprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, "%d similar %s errors",
123 ctx
->ErrorDebugCount
,
124 _mesa_enum_to_string(ctx
->ErrorValue
));
126 output_if_debug("Mesa", s
, GL_TRUE
);
128 ctx
->ErrorDebugCount
= 0;
134 * Report a warning (a recoverable error condition) to stderr if
135 * either DEBUG is defined or the MESA_DEBUG env var is set.
137 * \param ctx GL context.
138 * \param fmtString printf()-like format string.
141 _mesa_warning( struct gl_context
*ctx
, const char *fmtString
, ... )
143 char str
[MAX_DEBUG_MESSAGE_LENGTH
];
145 va_start( args
, fmtString
);
146 (void) vsnprintf( str
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
150 flush_delayed_errors( ctx
);
152 output_if_debug("Mesa warning", str
, GL_TRUE
);
157 * Report an internal implementation problem.
158 * Prints the message to stderr via fprintf().
160 * \param ctx GL context.
161 * \param fmtString problem description string.
164 _mesa_problem( const struct gl_context
*ctx
, const char *fmtString
, ... )
167 char str
[MAX_DEBUG_MESSAGE_LENGTH
];
168 static int numCalls
= 0;
175 va_start( args
, fmtString
);
176 vsnprintf( str
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
178 fprintf(stderr
, "Mesa " PACKAGE_VERSION
" implementation error: %s\n",
180 fprintf(stderr
, "Please report at " PACKAGE_BUGREPORT
"\n");
186 should_output(struct gl_context
*ctx
, GLenum error
, const char *fmtString
)
188 static GLint debug
= -1;
190 /* Check debug environment variable only once:
193 const char *debugEnv
= getenv("MESA_DEBUG");
196 if (debugEnv
&& strstr(debugEnv
, "silent"))
209 if (ctx
->ErrorValue
!= error
||
210 ctx
->ErrorDebugFmtString
!= fmtString
) {
211 flush_delayed_errors( ctx
);
212 ctx
->ErrorDebugFmtString
= fmtString
;
213 ctx
->ErrorDebugCount
= 0;
216 ctx
->ErrorDebugCount
++;
223 _mesa_gl_vdebugf(struct gl_context
*ctx
,
225 enum mesa_debug_source source
,
226 enum mesa_debug_type type
,
227 enum mesa_debug_severity severity
,
228 const char *fmtString
,
231 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
234 _mesa_debug_get_id(id
);
236 len
= vsnprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
237 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
)
238 /* message was truncated */
239 len
= MAX_DEBUG_MESSAGE_LENGTH
- 1;
241 _mesa_log_msg(ctx
, source
, type
, *id
, severity
, len
, s
);
246 _mesa_gl_debugf(struct gl_context
*ctx
,
248 enum mesa_debug_source source
,
249 enum mesa_debug_type type
,
250 enum mesa_debug_severity severity
,
251 const char *fmtString
, ...)
254 va_start(args
, fmtString
);
255 _mesa_gl_vdebugf(ctx
, id
, source
, type
, severity
, fmtString
, args
);
260 _mesa_gl_debug(struct gl_context
*ctx
,
262 enum mesa_debug_source source
,
263 enum mesa_debug_type type
,
264 enum mesa_debug_severity severity
,
267 _mesa_debug_get_id(id
);
269 size_t len
= strnlen(msg
, MAX_DEBUG_MESSAGE_LENGTH
);
270 if (len
< MAX_DEBUG_MESSAGE_LENGTH
) {
271 _mesa_log_msg(ctx
, source
, type
, *id
, severity
, len
, msg
);
275 /* limit the message to fit within KHR_debug buffers */
276 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
277 strncpy(s
, msg
, MAX_DEBUG_MESSAGE_LENGTH
);
278 s
[MAX_DEBUG_MESSAGE_LENGTH
- 1] = '\0';
279 len
= MAX_DEBUG_MESSAGE_LENGTH
- 1;
280 _mesa_log_msg(ctx
, source
, type
, *id
, severity
, len
, s
);
282 /* report the number of characters that were logged */
288 * Record an OpenGL state error. These usually occur when the user
289 * passes invalid parameters to a GL function.
291 * If debugging is enabled (either at compile-time via the DEBUG macro, or
292 * run-time via the MESA_DEBUG environment variable), report the error with
295 * \param ctx the GL context.
296 * \param error the error value.
297 * \param fmtString printf() style format string, followed by optional args
300 _mesa_error( struct gl_context
*ctx
, GLenum error
, const char *fmtString
, ... )
302 GLboolean do_output
, do_log
;
303 /* Ideally this would be set up by the caller, so that we had proper IDs
304 * per different message.
306 static GLuint error_msg_id
= 0;
308 _mesa_debug_get_id(&error_msg_id
);
310 do_output
= should_output(ctx
, error
, fmtString
);
312 simple_mtx_lock(&ctx
->DebugMutex
);
314 do_log
= _mesa_debug_is_message_enabled(ctx
->Debug
,
315 MESA_DEBUG_SOURCE_API
,
316 MESA_DEBUG_TYPE_ERROR
,
318 MESA_DEBUG_SEVERITY_HIGH
);
323 simple_mtx_unlock(&ctx
->DebugMutex
);
325 if (do_output
|| do_log
) {
326 char s
[MAX_DEBUG_MESSAGE_LENGTH
], s2
[MAX_DEBUG_MESSAGE_LENGTH
];
330 va_start(args
, fmtString
);
331 len
= vsnprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
334 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
) {
335 /* Too long error message. Whoever calls _mesa_error should use
342 len
= snprintf(s2
, MAX_DEBUG_MESSAGE_LENGTH
, "%s in %s",
343 _mesa_enum_to_string(error
), s
);
344 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
) {
350 /* Print the error to stderr if needed. */
352 output_if_debug("Mesa: User error", s2
, GL_TRUE
);
355 /* Log the error via ARB_debug_output if needed.*/
357 _mesa_log_msg(ctx
, MESA_DEBUG_SOURCE_API
, MESA_DEBUG_TYPE_ERROR
,
358 error_msg_id
, MESA_DEBUG_SEVERITY_HIGH
, len
, s2
);
362 /* Set the GL context error state for glGetError. */
363 if (ctx
->ErrorValue
== GL_NO_ERROR
)
364 ctx
->ErrorValue
= error
;
368 _mesa_error_no_memory(const char *caller
)
370 GET_CURRENT_CONTEXT(ctx
);
371 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "out of memory in %s", caller
);
375 * Report debug information. Print error message to stderr via fprintf().
376 * No-op if DEBUG mode not enabled.
378 * \param ctx GL context.
379 * \param fmtString printf()-style format string, followed by optional args.
382 _mesa_debug( const struct gl_context
*ctx
, const char *fmtString
, ... )
385 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
387 va_start(args
, fmtString
);
388 vsnprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
390 output_if_debug("Mesa", s
, GL_FALSE
);
398 _mesa_log(const char *fmtString
, ...)
400 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
402 va_start(args
, fmtString
);
403 vsnprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
405 output_if_debug(NULL
, s
, GL_FALSE
);
410 * Report debug information from the shader compiler via GL_ARB_debug_output.
412 * \param ctx GL context.
413 * \param type The namespace to which this message belongs.
414 * \param id The message ID within the given namespace.
415 * \param msg The message to output. Must be null-terminated.
418 _mesa_shader_debug(struct gl_context
*ctx
, GLenum type
, GLuint
*id
,
421 enum mesa_debug_source source
= MESA_DEBUG_SOURCE_SHADER_COMPILER
;
422 enum mesa_debug_severity severity
= MESA_DEBUG_SEVERITY_HIGH
;
425 _mesa_debug_get_id(id
);
429 /* Truncate the message if necessary. */
430 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
)
431 len
= MAX_DEBUG_MESSAGE_LENGTH
- 1;
433 _mesa_log_msg(ctx
, source
, type
, *id
, severity
, len
, msg
);