1848b8605Smrg/** 2848b8605Smrg * \file errors.c 3848b8605Smrg * Mesa debugging and error handling functions. 4848b8605Smrg */ 5848b8605Smrg 6848b8605Smrg/* 7848b8605Smrg * Mesa 3-D graphics library 8848b8605Smrg * 9848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 10848b8605Smrg * 11848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 12848b8605Smrg * copy of this software and associated documentation files (the "Software"), 13848b8605Smrg * to deal in the Software without restriction, including without limitation 14848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 16848b8605Smrg * Software is furnished to do so, subject to the following conditions: 17848b8605Smrg * 18848b8605Smrg * The above copyright notice and this permission notice shall be included 19848b8605Smrg * in all copies or substantial portions of the Software. 20848b8605Smrg * 21848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 28848b8605Smrg */ 29848b8605Smrg 30848b8605Smrg 31b8e80941Smrg#include <stdarg.h> 32b8e80941Smrg#include <stdio.h> 33848b8605Smrg#include "errors.h" 34848b8605Smrg#include "enums.h" 35848b8605Smrg#include "imports.h" 36848b8605Smrg#include "context.h" 37b8e80941Smrg#include "debug_output.h" 38848b8605Smrg 39848b8605Smrg 40b8e80941Smrgstatic FILE *LogFile = NULL; 41848b8605Smrg 42848b8605Smrg 43848b8605Smrgstatic void 44848b8605Smrgoutput_if_debug(const char *prefixString, const char *outputString, 45848b8605Smrg GLboolean newline) 46848b8605Smrg{ 47848b8605Smrg static int debug = -1; 48848b8605Smrg 49848b8605Smrg /* Init the local 'debug' var once. 50848b8605Smrg * Note: the _mesa_init_debug() function should have been called 51848b8605Smrg * by now so MESA_DEBUG_FLAGS will be initialized. 52848b8605Smrg */ 53848b8605Smrg if (debug == -1) { 54848b8605Smrg /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings, 55848b8605Smrg * etc to the named file. Otherwise, output to stderr. 56848b8605Smrg */ 57b8e80941Smrg const char *logFile = getenv("MESA_LOG_FILE"); 58848b8605Smrg if (logFile) 59b8e80941Smrg LogFile = fopen(logFile, "w"); 60b8e80941Smrg if (!LogFile) 61b8e80941Smrg LogFile = stderr; 62848b8605Smrg#ifdef DEBUG 63848b8605Smrg /* in debug builds, print messages unless MESA_DEBUG="silent" */ 64848b8605Smrg if (MESA_DEBUG_FLAGS & DEBUG_SILENT) 65848b8605Smrg debug = 0; 66848b8605Smrg else 67848b8605Smrg debug = 1; 68848b8605Smrg#else 69848b8605Smrg /* in release builds, be silent unless MESA_DEBUG is set */ 70b8e80941Smrg debug = getenv("MESA_DEBUG") != NULL; 71848b8605Smrg#endif 72848b8605Smrg } 73848b8605Smrg 74848b8605Smrg /* Now only print the string if we're required to do so. */ 75848b8605Smrg if (debug) { 76b8e80941Smrg if (prefixString) 77b8e80941Smrg fprintf(LogFile, "%s: %s", prefixString, outputString); 78b8e80941Smrg else 79b8e80941Smrg fprintf(LogFile, "%s", outputString); 80848b8605Smrg if (newline) 81b8e80941Smrg fprintf(LogFile, "\n"); 82b8e80941Smrg fflush(LogFile); 83848b8605Smrg 84b8e80941Smrg#if defined(_WIN32) 85848b8605Smrg /* stderr from windows applications without console is not usually 86848b8605Smrg * visible, so communicate with the debugger instead */ 87848b8605Smrg { 88848b8605Smrg char buf[4096]; 89848b8605Smrg _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : ""); 90848b8605Smrg OutputDebugStringA(buf); 91848b8605Smrg } 92848b8605Smrg#endif 93848b8605Smrg } 94848b8605Smrg} 95848b8605Smrg 96848b8605Smrg 97b8e80941Smrg/** 98b8e80941Smrg * Return the file handle to use for debug/logging. Defaults to stderr 99b8e80941Smrg * unless MESA_LOG_FILE is defined. 100b8e80941Smrg */ 101b8e80941SmrgFILE * 102b8e80941Smrg_mesa_get_log_file(void) 103b8e80941Smrg{ 104b8e80941Smrg assert(LogFile); 105b8e80941Smrg return LogFile; 106b8e80941Smrg} 107b8e80941Smrg 108b8e80941Smrg 109848b8605Smrg/** 110848b8605Smrg * When a new type of error is recorded, print a message describing 111848b8605Smrg * previous errors which were accumulated. 112848b8605Smrg */ 113848b8605Smrgstatic void 114848b8605Smrgflush_delayed_errors( struct gl_context *ctx ) 115848b8605Smrg{ 116848b8605Smrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 117848b8605Smrg 118848b8605Smrg if (ctx->ErrorDebugCount) { 119b8e80941Smrg _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors", 120848b8605Smrg ctx->ErrorDebugCount, 121b8e80941Smrg _mesa_enum_to_string(ctx->ErrorValue)); 122848b8605Smrg 123848b8605Smrg output_if_debug("Mesa", s, GL_TRUE); 124848b8605Smrg 125848b8605Smrg ctx->ErrorDebugCount = 0; 126848b8605Smrg } 127848b8605Smrg} 128848b8605Smrg 129848b8605Smrg 130848b8605Smrg/** 131848b8605Smrg * Report a warning (a recoverable error condition) to stderr if 132848b8605Smrg * either DEBUG is defined or the MESA_DEBUG env var is set. 133848b8605Smrg * 134848b8605Smrg * \param ctx GL context. 135848b8605Smrg * \param fmtString printf()-like format string. 136848b8605Smrg */ 137848b8605Smrgvoid 138848b8605Smrg_mesa_warning( struct gl_context *ctx, const char *fmtString, ... ) 139848b8605Smrg{ 140848b8605Smrg char str[MAX_DEBUG_MESSAGE_LENGTH]; 141848b8605Smrg va_list args; 142b8e80941Smrg va_start( args, fmtString ); 143848b8605Smrg (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args ); 144848b8605Smrg va_end( args ); 145b8e80941Smrg 146848b8605Smrg if (ctx) 147848b8605Smrg flush_delayed_errors( ctx ); 148848b8605Smrg 149848b8605Smrg output_if_debug("Mesa warning", str, GL_TRUE); 150848b8605Smrg} 151848b8605Smrg 152848b8605Smrg 153848b8605Smrg/** 154848b8605Smrg * Report an internal implementation problem. 155848b8605Smrg * Prints the message to stderr via fprintf(). 156848b8605Smrg * 157848b8605Smrg * \param ctx GL context. 158848b8605Smrg * \param fmtString problem description string. 159848b8605Smrg */ 160848b8605Smrgvoid 161848b8605Smrg_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) 162848b8605Smrg{ 163848b8605Smrg va_list args; 164848b8605Smrg char str[MAX_DEBUG_MESSAGE_LENGTH]; 165848b8605Smrg static int numCalls = 0; 166848b8605Smrg 167848b8605Smrg (void) ctx; 168848b8605Smrg 169848b8605Smrg if (numCalls < 50) { 170848b8605Smrg numCalls++; 171848b8605Smrg 172b8e80941Smrg va_start( args, fmtString ); 173848b8605Smrg _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args ); 174848b8605Smrg va_end( args ); 175b8e80941Smrg fprintf(stderr, "Mesa " PACKAGE_VERSION " implementation error: %s\n", 176b8e80941Smrg str); 177848b8605Smrg fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n"); 178848b8605Smrg } 179848b8605Smrg} 180848b8605Smrg 181848b8605Smrg 182848b8605Smrgstatic GLboolean 183848b8605Smrgshould_output(struct gl_context *ctx, GLenum error, const char *fmtString) 184848b8605Smrg{ 185848b8605Smrg static GLint debug = -1; 186848b8605Smrg 187848b8605Smrg /* Check debug environment variable only once: 188848b8605Smrg */ 189848b8605Smrg if (debug == -1) { 190b8e80941Smrg const char *debugEnv = getenv("MESA_DEBUG"); 191848b8605Smrg 192848b8605Smrg#ifdef DEBUG 193848b8605Smrg if (debugEnv && strstr(debugEnv, "silent")) 194848b8605Smrg debug = GL_FALSE; 195848b8605Smrg else 196848b8605Smrg debug = GL_TRUE; 197848b8605Smrg#else 198848b8605Smrg if (debugEnv) 199848b8605Smrg debug = GL_TRUE; 200848b8605Smrg else 201848b8605Smrg debug = GL_FALSE; 202848b8605Smrg#endif 203848b8605Smrg } 204848b8605Smrg 205848b8605Smrg if (debug) { 206848b8605Smrg if (ctx->ErrorValue != error || 207848b8605Smrg ctx->ErrorDebugFmtString != fmtString) { 208848b8605Smrg flush_delayed_errors( ctx ); 209848b8605Smrg ctx->ErrorDebugFmtString = fmtString; 210848b8605Smrg ctx->ErrorDebugCount = 0; 211848b8605Smrg return GL_TRUE; 212848b8605Smrg } 213848b8605Smrg ctx->ErrorDebugCount++; 214848b8605Smrg } 215848b8605Smrg return GL_FALSE; 216848b8605Smrg} 217848b8605Smrg 218848b8605Smrg 219848b8605Smrgvoid 220b8e80941Smrg_mesa_gl_vdebugf(struct gl_context *ctx, 221b8e80941Smrg GLuint *id, 222b8e80941Smrg enum mesa_debug_source source, 223b8e80941Smrg enum mesa_debug_type type, 224b8e80941Smrg enum mesa_debug_severity severity, 225b8e80941Smrg const char *fmtString, 226b8e80941Smrg va_list args) 227848b8605Smrg{ 228848b8605Smrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 229848b8605Smrg int len; 230848b8605Smrg 231b8e80941Smrg _mesa_debug_get_id(id); 232848b8605Smrg 233848b8605Smrg len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 234b8e80941Smrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) 235b8e80941Smrg /* message was truncated */ 236b8e80941Smrg len = MAX_DEBUG_MESSAGE_LENGTH - 1; 237b8e80941Smrg 238b8e80941Smrg _mesa_log_msg(ctx, source, type, *id, severity, len, s); 239b8e80941Smrg} 240b8e80941Smrg 241b8e80941Smrg 242b8e80941Smrgvoid 243b8e80941Smrg_mesa_gl_debugf(struct gl_context *ctx, 244b8e80941Smrg GLuint *id, 245b8e80941Smrg enum mesa_debug_source source, 246b8e80941Smrg enum mesa_debug_type type, 247b8e80941Smrg enum mesa_debug_severity severity, 248b8e80941Smrg const char *fmtString, ...) 249b8e80941Smrg{ 250b8e80941Smrg va_list args; 251b8e80941Smrg va_start(args, fmtString); 252b8e80941Smrg _mesa_gl_vdebugf(ctx, id, source, type, severity, fmtString, args); 253848b8605Smrg va_end(args); 254b8e80941Smrg} 255b8e80941Smrg 256b8e80941Smrgsize_t 257b8e80941Smrg_mesa_gl_debug(struct gl_context *ctx, 258b8e80941Smrg GLuint *id, 259b8e80941Smrg enum mesa_debug_source source, 260b8e80941Smrg enum mesa_debug_type type, 261b8e80941Smrg enum mesa_debug_severity severity, 262b8e80941Smrg const char *msg) 263b8e80941Smrg{ 264b8e80941Smrg _mesa_debug_get_id(id); 265848b8605Smrg 266b8e80941Smrg size_t len = strnlen(msg, MAX_DEBUG_MESSAGE_LENGTH); 267b8e80941Smrg if (len < MAX_DEBUG_MESSAGE_LENGTH) { 268b8e80941Smrg _mesa_log_msg(ctx, source, type, *id, severity, len, msg); 269b8e80941Smrg return len; 270b8e80941Smrg } 271b8e80941Smrg 272b8e80941Smrg /* limit the message to fit within KHR_debug buffers */ 273b8e80941Smrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 274b8e80941Smrg strncpy(s, msg, MAX_DEBUG_MESSAGE_LENGTH); 275b8e80941Smrg s[MAX_DEBUG_MESSAGE_LENGTH - 1] = '\0'; 276b8e80941Smrg len = MAX_DEBUG_MESSAGE_LENGTH - 1; 277b8e80941Smrg _mesa_log_msg(ctx, source, type, *id, severity, len, s); 278b8e80941Smrg 279b8e80941Smrg /* report the number of characters that were logged */ 280b8e80941Smrg return len; 281848b8605Smrg} 282848b8605Smrg 283848b8605Smrg 284848b8605Smrg/** 285848b8605Smrg * Record an OpenGL state error. These usually occur when the user 286848b8605Smrg * passes invalid parameters to a GL function. 287848b8605Smrg * 288848b8605Smrg * If debugging is enabled (either at compile-time via the DEBUG macro, or 289848b8605Smrg * run-time via the MESA_DEBUG environment variable), report the error with 290848b8605Smrg * _mesa_debug(). 291b8e80941Smrg * 292848b8605Smrg * \param ctx the GL context. 293848b8605Smrg * \param error the error value. 294848b8605Smrg * \param fmtString printf() style format string, followed by optional args 295848b8605Smrg */ 296848b8605Smrgvoid 297848b8605Smrg_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) 298848b8605Smrg{ 299848b8605Smrg GLboolean do_output, do_log; 300848b8605Smrg /* Ideally this would be set up by the caller, so that we had proper IDs 301848b8605Smrg * per different message. 302848b8605Smrg */ 303848b8605Smrg static GLuint error_msg_id = 0; 304848b8605Smrg 305b8e80941Smrg _mesa_debug_get_id(&error_msg_id); 306848b8605Smrg 307848b8605Smrg do_output = should_output(ctx, error, fmtString); 308b8e80941Smrg 309b8e80941Smrg simple_mtx_lock(&ctx->DebugMutex); 310848b8605Smrg if (ctx->Debug) { 311b8e80941Smrg do_log = _mesa_debug_is_message_enabled(ctx->Debug, 312b8e80941Smrg MESA_DEBUG_SOURCE_API, 313b8e80941Smrg MESA_DEBUG_TYPE_ERROR, 314b8e80941Smrg error_msg_id, 315b8e80941Smrg MESA_DEBUG_SEVERITY_HIGH); 316848b8605Smrg } 317848b8605Smrg else { 318848b8605Smrg do_log = GL_FALSE; 319848b8605Smrg } 320b8e80941Smrg simple_mtx_unlock(&ctx->DebugMutex); 321848b8605Smrg 322848b8605Smrg if (do_output || do_log) { 323848b8605Smrg char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH]; 324848b8605Smrg int len; 325848b8605Smrg va_list args; 326848b8605Smrg 327848b8605Smrg va_start(args, fmtString); 328848b8605Smrg len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 329848b8605Smrg va_end(args); 330848b8605Smrg 331848b8605Smrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 332848b8605Smrg /* Too long error message. Whoever calls _mesa_error should use 333848b8605Smrg * shorter strings. 334848b8605Smrg */ 335b8e80941Smrg assert(0); 336848b8605Smrg return; 337848b8605Smrg } 338848b8605Smrg 339848b8605Smrg len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s", 340b8e80941Smrg _mesa_enum_to_string(error), s); 341848b8605Smrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 342848b8605Smrg /* Same as above. */ 343b8e80941Smrg assert(0); 344848b8605Smrg return; 345848b8605Smrg } 346848b8605Smrg 347848b8605Smrg /* Print the error to stderr if needed. */ 348848b8605Smrg if (do_output) { 349848b8605Smrg output_if_debug("Mesa: User error", s2, GL_TRUE); 350848b8605Smrg } 351848b8605Smrg 352848b8605Smrg /* Log the error via ARB_debug_output if needed.*/ 353848b8605Smrg if (do_log) { 354b8e80941Smrg _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR, 355b8e80941Smrg error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2); 356848b8605Smrg } 357848b8605Smrg } 358848b8605Smrg 359848b8605Smrg /* Set the GL context error state for glGetError. */ 360b8e80941Smrg if (ctx->ErrorValue == GL_NO_ERROR) 361b8e80941Smrg ctx->ErrorValue = error; 362848b8605Smrg} 363848b8605Smrg 364848b8605Smrgvoid 365848b8605Smrg_mesa_error_no_memory(const char *caller) 366848b8605Smrg{ 367848b8605Smrg GET_CURRENT_CONTEXT(ctx); 368848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller); 369848b8605Smrg} 370848b8605Smrg 371848b8605Smrg/** 372848b8605Smrg * Report debug information. Print error message to stderr via fprintf(). 373848b8605Smrg * No-op if DEBUG mode not enabled. 374b8e80941Smrg * 375848b8605Smrg * \param ctx GL context. 376848b8605Smrg * \param fmtString printf()-style format string, followed by optional args. 377848b8605Smrg */ 378848b8605Smrgvoid 379848b8605Smrg_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) 380848b8605Smrg{ 381848b8605Smrg#ifdef DEBUG 382848b8605Smrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 383848b8605Smrg va_list args; 384848b8605Smrg va_start(args, fmtString); 385848b8605Smrg _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 386848b8605Smrg va_end(args); 387848b8605Smrg output_if_debug("Mesa", s, GL_FALSE); 388848b8605Smrg#endif /* DEBUG */ 389848b8605Smrg (void) ctx; 390848b8605Smrg (void) fmtString; 391848b8605Smrg} 392848b8605Smrg 393848b8605Smrg 394b8e80941Smrgvoid 395b8e80941Smrg_mesa_log(const char *fmtString, ...) 396b8e80941Smrg{ 397b8e80941Smrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 398b8e80941Smrg va_list args; 399b8e80941Smrg va_start(args, fmtString); 400b8e80941Smrg _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 401b8e80941Smrg va_end(args); 402b8e80941Smrg output_if_debug("", s, GL_FALSE); 403b8e80941Smrg} 404b8e80941Smrg 405b8e80941Smrg 406848b8605Smrg/** 407848b8605Smrg * Report debug information from the shader compiler via GL_ARB_debug_output. 408848b8605Smrg * 409848b8605Smrg * \param ctx GL context. 410848b8605Smrg * \param type The namespace to which this message belongs. 411848b8605Smrg * \param id The message ID within the given namespace. 412b8e80941Smrg * \param msg The message to output. Must be null-terminated. 413848b8605Smrg */ 414848b8605Smrgvoid 415b8e80941Smrg_mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id, 416b8e80941Smrg const char *msg) 417848b8605Smrg{ 418848b8605Smrg enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER; 419848b8605Smrg enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH; 420b8e80941Smrg int len; 421848b8605Smrg 422b8e80941Smrg _mesa_debug_get_id(id); 423848b8605Smrg 424b8e80941Smrg len = strlen(msg); 425848b8605Smrg 426848b8605Smrg /* Truncate the message if necessary. */ 427848b8605Smrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) 428848b8605Smrg len = MAX_DEBUG_MESSAGE_LENGTH - 1; 429848b8605Smrg 430b8e80941Smrg _mesa_log_msg(ctx, source, type, *id, severity, len, msg); 431848b8605Smrg} 432