1af69d88dSmrg/** 2af69d88dSmrg * \file errors.c 3af69d88dSmrg * Mesa debugging and error handling functions. 4af69d88dSmrg */ 5af69d88dSmrg 6af69d88dSmrg/* 7af69d88dSmrg * Mesa 3-D graphics library 8af69d88dSmrg * 9af69d88dSmrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 10af69d88dSmrg * 11af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 12af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 13af69d88dSmrg * to deal in the Software without restriction, including without limitation 14af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 16af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 17af69d88dSmrg * 18af69d88dSmrg * The above copyright notice and this permission notice shall be included 19af69d88dSmrg * in all copies or substantial portions of the Software. 20af69d88dSmrg * 21af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 28af69d88dSmrg */ 29af69d88dSmrg 30af69d88dSmrg 3101e04c3fSmrg#include <stdarg.h> 3201e04c3fSmrg#include <stdio.h> 33af69d88dSmrg#include "errors.h" 34af69d88dSmrg#include "enums.h" 357ec681f3Smrg 36af69d88dSmrg#include "context.h" 3701e04c3fSmrg#include "debug_output.h" 38af69d88dSmrg 39af69d88dSmrg 4001e04c3fSmrgstatic FILE *LogFile = NULL; 41af69d88dSmrg 42af69d88dSmrg 43af69d88dSmrgstatic void 44af69d88dSmrgoutput_if_debug(const char *prefixString, const char *outputString, 45af69d88dSmrg GLboolean newline) 46af69d88dSmrg{ 47af69d88dSmrg static int debug = -1; 48af69d88dSmrg 49af69d88dSmrg /* Init the local 'debug' var once. 50af69d88dSmrg * Note: the _mesa_init_debug() function should have been called 51af69d88dSmrg * by now so MESA_DEBUG_FLAGS will be initialized. 52af69d88dSmrg */ 53af69d88dSmrg if (debug == -1) { 54af69d88dSmrg /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings, 55af69d88dSmrg * etc to the named file. Otherwise, output to stderr. 56af69d88dSmrg */ 5701e04c3fSmrg const char *logFile = getenv("MESA_LOG_FILE"); 58af69d88dSmrg if (logFile) 5901e04c3fSmrg LogFile = fopen(logFile, "w"); 6001e04c3fSmrg if (!LogFile) 6101e04c3fSmrg LogFile = stderr; 627ec681f3Smrg#ifndef NDEBUG 63af69d88dSmrg /* in debug builds, print messages unless MESA_DEBUG="silent" */ 64af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_SILENT) 65af69d88dSmrg debug = 0; 66af69d88dSmrg else 67af69d88dSmrg debug = 1; 68af69d88dSmrg#else 697ec681f3Smrg const char *env = getenv("MESA_DEBUG"); 707ec681f3Smrg debug = env && strstr(env, "silent") == NULL; 71af69d88dSmrg#endif 72af69d88dSmrg } 73af69d88dSmrg 74af69d88dSmrg /* Now only print the string if we're required to do so. */ 75af69d88dSmrg if (debug) { 7601e04c3fSmrg if (prefixString) 7701e04c3fSmrg fprintf(LogFile, "%s: %s", prefixString, outputString); 7801e04c3fSmrg else 7901e04c3fSmrg fprintf(LogFile, "%s", outputString); 80af69d88dSmrg if (newline) 8101e04c3fSmrg fprintf(LogFile, "\n"); 8201e04c3fSmrg fflush(LogFile); 83af69d88dSmrg 8401e04c3fSmrg#if defined(_WIN32) 857ec681f3Smrg /* stderr from windows applications without console is not usually 867ec681f3Smrg * visible, so communicate with the debugger instead */ 87af69d88dSmrg { 88af69d88dSmrg char buf[4096]; 897ec681f3Smrg if (prefixString) 907ec681f3Smrg snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : ""); 917ec681f3Smrg else 927ec681f3Smrg snprintf(buf, sizeof(buf), "%s%s", outputString, newline ? "\n" : ""); 93af69d88dSmrg OutputDebugStringA(buf); 94af69d88dSmrg } 95af69d88dSmrg#endif 96af69d88dSmrg } 97af69d88dSmrg} 98af69d88dSmrg 99af69d88dSmrg 10001e04c3fSmrg/** 10101e04c3fSmrg * Return the file handle to use for debug/logging. Defaults to stderr 10201e04c3fSmrg * unless MESA_LOG_FILE is defined. 10301e04c3fSmrg */ 10401e04c3fSmrgFILE * 10501e04c3fSmrg_mesa_get_log_file(void) 10601e04c3fSmrg{ 10701e04c3fSmrg assert(LogFile); 10801e04c3fSmrg return LogFile; 10901e04c3fSmrg} 11001e04c3fSmrg 11101e04c3fSmrg 112af69d88dSmrg/** 113af69d88dSmrg * When a new type of error is recorded, print a message describing 114af69d88dSmrg * previous errors which were accumulated. 115af69d88dSmrg */ 116af69d88dSmrgstatic void 117af69d88dSmrgflush_delayed_errors( struct gl_context *ctx ) 118af69d88dSmrg{ 119af69d88dSmrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 120af69d88dSmrg 121af69d88dSmrg if (ctx->ErrorDebugCount) { 1227ec681f3Smrg snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors", 123af69d88dSmrg ctx->ErrorDebugCount, 12401e04c3fSmrg _mesa_enum_to_string(ctx->ErrorValue)); 125af69d88dSmrg 126af69d88dSmrg output_if_debug("Mesa", s, GL_TRUE); 127af69d88dSmrg 128af69d88dSmrg ctx->ErrorDebugCount = 0; 129af69d88dSmrg } 130af69d88dSmrg} 131af69d88dSmrg 132af69d88dSmrg 133af69d88dSmrg/** 134af69d88dSmrg * Report a warning (a recoverable error condition) to stderr if 135af69d88dSmrg * either DEBUG is defined or the MESA_DEBUG env var is set. 136af69d88dSmrg * 137af69d88dSmrg * \param ctx GL context. 138af69d88dSmrg * \param fmtString printf()-like format string. 139af69d88dSmrg */ 140af69d88dSmrgvoid 141af69d88dSmrg_mesa_warning( struct gl_context *ctx, const char *fmtString, ... ) 142af69d88dSmrg{ 143af69d88dSmrg char str[MAX_DEBUG_MESSAGE_LENGTH]; 144af69d88dSmrg va_list args; 14501e04c3fSmrg va_start( args, fmtString ); 1467ec681f3Smrg (void) vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args ); 147af69d88dSmrg va_end( args ); 14801e04c3fSmrg 149af69d88dSmrg if (ctx) 150af69d88dSmrg flush_delayed_errors( ctx ); 151af69d88dSmrg 152af69d88dSmrg output_if_debug("Mesa warning", str, GL_TRUE); 153af69d88dSmrg} 154af69d88dSmrg 155af69d88dSmrg 156af69d88dSmrg/** 157af69d88dSmrg * Report an internal implementation problem. 158af69d88dSmrg * Prints the message to stderr via fprintf(). 159af69d88dSmrg * 160af69d88dSmrg * \param ctx GL context. 161af69d88dSmrg * \param fmtString problem description string. 162af69d88dSmrg */ 163af69d88dSmrgvoid 164af69d88dSmrg_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) 165af69d88dSmrg{ 166af69d88dSmrg va_list args; 167af69d88dSmrg char str[MAX_DEBUG_MESSAGE_LENGTH]; 168af69d88dSmrg static int numCalls = 0; 169af69d88dSmrg 170af69d88dSmrg (void) ctx; 171af69d88dSmrg 172af69d88dSmrg if (numCalls < 50) { 173af69d88dSmrg numCalls++; 174af69d88dSmrg 17501e04c3fSmrg va_start( args, fmtString ); 1767ec681f3Smrg vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args ); 177af69d88dSmrg va_end( args ); 17801e04c3fSmrg fprintf(stderr, "Mesa " PACKAGE_VERSION " implementation error: %s\n", 17901e04c3fSmrg str); 180af69d88dSmrg fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n"); 181af69d88dSmrg } 182af69d88dSmrg} 183af69d88dSmrg 184af69d88dSmrg 185af69d88dSmrgstatic GLboolean 186af69d88dSmrgshould_output(struct gl_context *ctx, GLenum error, const char *fmtString) 187af69d88dSmrg{ 188af69d88dSmrg static GLint debug = -1; 189af69d88dSmrg 190af69d88dSmrg /* Check debug environment variable only once: 191af69d88dSmrg */ 192af69d88dSmrg if (debug == -1) { 19301e04c3fSmrg const char *debugEnv = getenv("MESA_DEBUG"); 194af69d88dSmrg 1957ec681f3Smrg#ifndef NDEBUG 196af69d88dSmrg if (debugEnv && strstr(debugEnv, "silent")) 197af69d88dSmrg debug = GL_FALSE; 198af69d88dSmrg else 199af69d88dSmrg debug = GL_TRUE; 200af69d88dSmrg#else 201af69d88dSmrg if (debugEnv) 202af69d88dSmrg debug = GL_TRUE; 203af69d88dSmrg else 204af69d88dSmrg debug = GL_FALSE; 205af69d88dSmrg#endif 206af69d88dSmrg } 207af69d88dSmrg 208af69d88dSmrg if (debug) { 209af69d88dSmrg if (ctx->ErrorValue != error || 210af69d88dSmrg ctx->ErrorDebugFmtString != fmtString) { 211af69d88dSmrg flush_delayed_errors( ctx ); 212af69d88dSmrg ctx->ErrorDebugFmtString = fmtString; 213af69d88dSmrg ctx->ErrorDebugCount = 0; 214af69d88dSmrg return GL_TRUE; 215af69d88dSmrg } 216af69d88dSmrg ctx->ErrorDebugCount++; 217af69d88dSmrg } 218af69d88dSmrg return GL_FALSE; 219af69d88dSmrg} 220af69d88dSmrg 221af69d88dSmrg 22201e04c3fSmrgvoid 223a8bb7a65Smaya_mesa_gl_vdebugf(struct gl_context *ctx, 224a8bb7a65Smaya GLuint *id, 225a8bb7a65Smaya enum mesa_debug_source source, 226a8bb7a65Smaya enum mesa_debug_type type, 227a8bb7a65Smaya enum mesa_debug_severity severity, 228a8bb7a65Smaya const char *fmtString, 229a8bb7a65Smaya va_list args) 23001e04c3fSmrg{ 23101e04c3fSmrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 23201e04c3fSmrg int len; 23301e04c3fSmrg 23401e04c3fSmrg _mesa_debug_get_id(id); 23501e04c3fSmrg 2367ec681f3Smrg len = vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 237993e1d59Smrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) 238993e1d59Smrg /* message was truncated */ 239993e1d59Smrg len = MAX_DEBUG_MESSAGE_LENGTH - 1; 24001e04c3fSmrg 24101e04c3fSmrg _mesa_log_msg(ctx, source, type, *id, severity, len, s); 24201e04c3fSmrg} 24301e04c3fSmrg 24401e04c3fSmrg 245af69d88dSmrgvoid 246a8bb7a65Smaya_mesa_gl_debugf(struct gl_context *ctx, 247a8bb7a65Smaya GLuint *id, 248a8bb7a65Smaya enum mesa_debug_source source, 249a8bb7a65Smaya enum mesa_debug_type type, 250a8bb7a65Smaya enum mesa_debug_severity severity, 251a8bb7a65Smaya const char *fmtString, ...) 252a8bb7a65Smaya{ 253a8bb7a65Smaya va_list args; 254a8bb7a65Smaya va_start(args, fmtString); 255a8bb7a65Smaya _mesa_gl_vdebugf(ctx, id, source, type, severity, fmtString, args); 256a8bb7a65Smaya va_end(args); 257a8bb7a65Smaya} 258a8bb7a65Smaya 259a8bb7a65Smayasize_t 260af69d88dSmrg_mesa_gl_debug(struct gl_context *ctx, 261af69d88dSmrg GLuint *id, 26201e04c3fSmrg enum mesa_debug_source source, 263af69d88dSmrg enum mesa_debug_type type, 264af69d88dSmrg enum mesa_debug_severity severity, 265a8bb7a65Smaya const char *msg) 266af69d88dSmrg{ 267a8bb7a65Smaya _mesa_debug_get_id(id); 268a8bb7a65Smaya 269a8bb7a65Smaya size_t len = strnlen(msg, MAX_DEBUG_MESSAGE_LENGTH); 270a8bb7a65Smaya if (len < MAX_DEBUG_MESSAGE_LENGTH) { 271a8bb7a65Smaya _mesa_log_msg(ctx, source, type, *id, severity, len, msg); 272a8bb7a65Smaya return len; 273a8bb7a65Smaya } 274a8bb7a65Smaya 275a8bb7a65Smaya /* limit the message to fit within KHR_debug buffers */ 276a8bb7a65Smaya char s[MAX_DEBUG_MESSAGE_LENGTH]; 277a8bb7a65Smaya strncpy(s, msg, MAX_DEBUG_MESSAGE_LENGTH); 278a8bb7a65Smaya s[MAX_DEBUG_MESSAGE_LENGTH - 1] = '\0'; 279a8bb7a65Smaya len = MAX_DEBUG_MESSAGE_LENGTH - 1; 280a8bb7a65Smaya _mesa_log_msg(ctx, source, type, *id, severity, len, s); 281a8bb7a65Smaya 282a8bb7a65Smaya /* report the number of characters that were logged */ 283a8bb7a65Smaya return len; 284af69d88dSmrg} 285af69d88dSmrg 286af69d88dSmrg 287af69d88dSmrg/** 288af69d88dSmrg * Record an OpenGL state error. These usually occur when the user 289af69d88dSmrg * passes invalid parameters to a GL function. 290af69d88dSmrg * 291af69d88dSmrg * If debugging is enabled (either at compile-time via the DEBUG macro, or 292af69d88dSmrg * run-time via the MESA_DEBUG environment variable), report the error with 293af69d88dSmrg * _mesa_debug(). 29401e04c3fSmrg * 295af69d88dSmrg * \param ctx the GL context. 296af69d88dSmrg * \param error the error value. 297af69d88dSmrg * \param fmtString printf() style format string, followed by optional args 298af69d88dSmrg */ 299af69d88dSmrgvoid 300af69d88dSmrg_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) 301af69d88dSmrg{ 302af69d88dSmrg GLboolean do_output, do_log; 303af69d88dSmrg /* Ideally this would be set up by the caller, so that we had proper IDs 304af69d88dSmrg * per different message. 305af69d88dSmrg */ 306af69d88dSmrg static GLuint error_msg_id = 0; 307af69d88dSmrg 30801e04c3fSmrg _mesa_debug_get_id(&error_msg_id); 309af69d88dSmrg 310af69d88dSmrg do_output = should_output(ctx, error, fmtString); 31101e04c3fSmrg 31201e04c3fSmrg simple_mtx_lock(&ctx->DebugMutex); 313af69d88dSmrg if (ctx->Debug) { 31401e04c3fSmrg do_log = _mesa_debug_is_message_enabled(ctx->Debug, 31501e04c3fSmrg MESA_DEBUG_SOURCE_API, 31601e04c3fSmrg MESA_DEBUG_TYPE_ERROR, 31701e04c3fSmrg error_msg_id, 31801e04c3fSmrg MESA_DEBUG_SEVERITY_HIGH); 319af69d88dSmrg } 320af69d88dSmrg else { 321af69d88dSmrg do_log = GL_FALSE; 322af69d88dSmrg } 32301e04c3fSmrg simple_mtx_unlock(&ctx->DebugMutex); 324af69d88dSmrg 325af69d88dSmrg if (do_output || do_log) { 326af69d88dSmrg char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH]; 327af69d88dSmrg int len; 328af69d88dSmrg va_list args; 329af69d88dSmrg 330af69d88dSmrg va_start(args, fmtString); 3317ec681f3Smrg len = vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 332af69d88dSmrg va_end(args); 333af69d88dSmrg 334af69d88dSmrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 335af69d88dSmrg /* Too long error message. Whoever calls _mesa_error should use 336af69d88dSmrg * shorter strings. 337af69d88dSmrg */ 33801e04c3fSmrg assert(0); 339af69d88dSmrg return; 340af69d88dSmrg } 341af69d88dSmrg 3427ec681f3Smrg len = snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s", 34301e04c3fSmrg _mesa_enum_to_string(error), s); 344af69d88dSmrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) { 345af69d88dSmrg /* Same as above. */ 34601e04c3fSmrg assert(0); 347af69d88dSmrg return; 348af69d88dSmrg } 349af69d88dSmrg 350af69d88dSmrg /* Print the error to stderr if needed. */ 351af69d88dSmrg if (do_output) { 352af69d88dSmrg output_if_debug("Mesa: User error", s2, GL_TRUE); 353af69d88dSmrg } 354af69d88dSmrg 355af69d88dSmrg /* Log the error via ARB_debug_output if needed.*/ 356af69d88dSmrg if (do_log) { 35701e04c3fSmrg _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR, 35801e04c3fSmrg error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2); 359af69d88dSmrg } 360af69d88dSmrg } 361af69d88dSmrg 362af69d88dSmrg /* Set the GL context error state for glGetError. */ 36301e04c3fSmrg if (ctx->ErrorValue == GL_NO_ERROR) 36401e04c3fSmrg ctx->ErrorValue = error; 365af69d88dSmrg} 366af69d88dSmrg 367af69d88dSmrgvoid 368af69d88dSmrg_mesa_error_no_memory(const char *caller) 369af69d88dSmrg{ 370af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 371af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller); 372af69d88dSmrg} 373af69d88dSmrg 374af69d88dSmrg/** 375af69d88dSmrg * Report debug information. Print error message to stderr via fprintf(). 376af69d88dSmrg * No-op if DEBUG mode not enabled. 37701e04c3fSmrg * 378af69d88dSmrg * \param ctx GL context. 379af69d88dSmrg * \param fmtString printf()-style format string, followed by optional args. 380af69d88dSmrg */ 381af69d88dSmrgvoid 382af69d88dSmrg_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) 383af69d88dSmrg{ 3847ec681f3Smrg#ifndef NDEBUG 385af69d88dSmrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 386af69d88dSmrg va_list args; 387af69d88dSmrg va_start(args, fmtString); 3887ec681f3Smrg vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 389af69d88dSmrg va_end(args); 390af69d88dSmrg output_if_debug("Mesa", s, GL_FALSE); 391af69d88dSmrg#endif /* DEBUG */ 392af69d88dSmrg (void) ctx; 393af69d88dSmrg (void) fmtString; 394af69d88dSmrg} 395af69d88dSmrg 396af69d88dSmrg 39701e04c3fSmrgvoid 39801e04c3fSmrg_mesa_log(const char *fmtString, ...) 39901e04c3fSmrg{ 40001e04c3fSmrg char s[MAX_DEBUG_MESSAGE_LENGTH]; 40101e04c3fSmrg va_list args; 40201e04c3fSmrg va_start(args, fmtString); 4037ec681f3Smrg vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); 40401e04c3fSmrg va_end(args); 4057ec681f3Smrg output_if_debug(NULL, s, GL_FALSE); 40601e04c3fSmrg} 40701e04c3fSmrg 40801e04c3fSmrg 409af69d88dSmrg/** 410af69d88dSmrg * Report debug information from the shader compiler via GL_ARB_debug_output. 411af69d88dSmrg * 412af69d88dSmrg * \param ctx GL context. 413af69d88dSmrg * \param type The namespace to which this message belongs. 414af69d88dSmrg * \param id The message ID within the given namespace. 41501e04c3fSmrg * \param msg The message to output. Must be null-terminated. 416af69d88dSmrg */ 417af69d88dSmrgvoid 41801e04c3fSmrg_mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id, 41901e04c3fSmrg const char *msg) 420af69d88dSmrg{ 421af69d88dSmrg enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER; 422af69d88dSmrg enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH; 42301e04c3fSmrg int len; 424af69d88dSmrg 42501e04c3fSmrg _mesa_debug_get_id(id); 426af69d88dSmrg 42701e04c3fSmrg len = strlen(msg); 428af69d88dSmrg 429af69d88dSmrg /* Truncate the message if necessary. */ 430af69d88dSmrg if (len >= MAX_DEBUG_MESSAGE_LENGTH) 431af69d88dSmrg len = MAX_DEBUG_MESSAGE_LENGTH - 1; 432af69d88dSmrg 43301e04c3fSmrg _mesa_log_msg(ctx, source, type, *id, severity, len, msg); 434af69d88dSmrg} 4357ec681f3Smrg 4367ec681f3Smrg/** 4377ec681f3Smrg * Set the parameter as the current GL error. Used by glthread. 4387ec681f3Smrg */ 4397ec681f3Smrgvoid GLAPIENTRY 4407ec681f3Smrg_mesa_InternalSetError(GLenum error) 4417ec681f3Smrg{ 4427ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 4437ec681f3Smrg _mesa_error(ctx, error, "glthread"); 4447ec681f3Smrg} 445