Home | History | Annotate | Download | only in main
      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 
     39 
     40 static FILE *LogFile = NULL;
     41 
     42 
     43 static void
     44 output_if_debug(const char *prefixString, const char *outputString,
     45                 GLboolean newline)
     46 {
     47    static int debug = -1;
     48 
     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.
     52     */
     53    if (debug == -1) {
     54       /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
     55        * etc to the named file.  Otherwise, output to stderr.
     56        */
     57       const char *logFile = getenv("MESA_LOG_FILE");
     58       if (logFile)
     59          LogFile = fopen(logFile, "w");
     60       if (!LogFile)
     61          LogFile = stderr;
     62 #ifdef DEBUG
     63       /* in debug builds, print messages unless MESA_DEBUG="silent" */
     64       if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
     65          debug = 0;
     66       else
     67          debug = 1;
     68 #else
     69       /* in release builds, be silent unless MESA_DEBUG is set */
     70       debug = getenv("MESA_DEBUG") != NULL;
     71 #endif
     72    }
     73 
     74    /* Now only print the string if we're required to do so. */
     75    if (debug) {
     76       if (prefixString)
     77          fprintf(LogFile, "%s: %s", prefixString, outputString);
     78       else
     79          fprintf(LogFile, "%s", outputString);
     80       if (newline)
     81          fprintf(LogFile, "\n");
     82       fflush(LogFile);
     83 
     84 #if defined(_WIN32)
     85       /* stderr from windows applications without console is not usually
     86        * visible, so communicate with the debugger instead */
     87       {
     88          char buf[4096];
     89          _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
     90          OutputDebugStringA(buf);
     91       }
     92 #endif
     93    }
     94 }
     95 
     96 
     97 /**
     98  * Return the file handle to use for debug/logging.  Defaults to stderr
     99  * unless MESA_LOG_FILE is defined.
    100  */
    101 FILE *
    102 _mesa_get_log_file(void)
    103 {
    104    assert(LogFile);
    105    return LogFile;
    106 }
    107 
    108 
    109 /**
    110  * When a new type of error is recorded, print a message describing
    111  * previous errors which were accumulated.
    112  */
    113 static void
    114 flush_delayed_errors( struct gl_context *ctx )
    115 {
    116    char s[MAX_DEBUG_MESSAGE_LENGTH];
    117 
    118    if (ctx->ErrorDebugCount) {
    119       _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
    120                      ctx->ErrorDebugCount,
    121                      _mesa_enum_to_string(ctx->ErrorValue));
    122 
    123       output_if_debug("Mesa", s, GL_TRUE);
    124 
    125       ctx->ErrorDebugCount = 0;
    126    }
    127 }
    128 
    129 
    130 /**
    131  * Report a warning (a recoverable error condition) to stderr if
    132  * either DEBUG is defined or the MESA_DEBUG env var is set.
    133  *
    134  * \param ctx GL context.
    135  * \param fmtString printf()-like format string.
    136  */
    137 void
    138 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
    139 {
    140    char str[MAX_DEBUG_MESSAGE_LENGTH];
    141    va_list args;
    142    va_start( args, fmtString );
    143    (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
    144    va_end( args );
    145 
    146    if (ctx)
    147       flush_delayed_errors( ctx );
    148 
    149    output_if_debug("Mesa warning", str, GL_TRUE);
    150 }
    151 
    152 
    153 /**
    154  * Report an internal implementation problem.
    155  * Prints the message to stderr via fprintf().
    156  *
    157  * \param ctx GL context.
    158  * \param fmtString problem description string.
    159  */
    160 void
    161 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
    162 {
    163    va_list args;
    164    char str[MAX_DEBUG_MESSAGE_LENGTH];
    165    static int numCalls = 0;
    166 
    167    (void) ctx;
    168 
    169    if (numCalls < 50) {
    170       numCalls++;
    171 
    172       va_start( args, fmtString );
    173       _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
    174       va_end( args );
    175       fprintf(stderr, "Mesa %s implementation error: %s\n",
    176               PACKAGE_VERSION, str);
    177       fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
    178    }
    179 }
    180 
    181 
    182 static GLboolean
    183 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
    184 {
    185    static GLint debug = -1;
    186 
    187    /* Check debug environment variable only once:
    188     */
    189    if (debug == -1) {
    190       const char *debugEnv = getenv("MESA_DEBUG");
    191 
    192 #ifdef DEBUG
    193       if (debugEnv && strstr(debugEnv, "silent"))
    194          debug = GL_FALSE;
    195       else
    196          debug = GL_TRUE;
    197 #else
    198       if (debugEnv)
    199          debug = GL_TRUE;
    200       else
    201          debug = GL_FALSE;
    202 #endif
    203    }
    204 
    205    if (debug) {
    206       if (ctx->ErrorValue != error ||
    207           ctx->ErrorDebugFmtString != fmtString) {
    208          flush_delayed_errors( ctx );
    209          ctx->ErrorDebugFmtString = fmtString;
    210          ctx->ErrorDebugCount = 0;
    211          return GL_TRUE;
    212       }
    213       ctx->ErrorDebugCount++;
    214    }
    215    return GL_FALSE;
    216 }
    217 
    218 
    219 void
    220 _mesa_gl_vdebug(struct gl_context *ctx,
    221                 GLuint *id,
    222                 enum mesa_debug_source source,
    223                 enum mesa_debug_type type,
    224                 enum mesa_debug_severity severity,
    225                 const char *fmtString,
    226                 va_list args)
    227 {
    228    char s[MAX_DEBUG_MESSAGE_LENGTH];
    229    int len;
    230 
    231    _mesa_debug_get_id(id);
    232 
    233    len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
    234 
    235    _mesa_log_msg(ctx, source, type, *id, severity, len, s);
    236 }
    237 
    238 
    239 void
    240 _mesa_gl_debug(struct gl_context *ctx,
    241                GLuint *id,
    242                enum mesa_debug_source source,
    243                enum mesa_debug_type type,
    244                enum mesa_debug_severity severity,
    245                const char *fmtString, ...)
    246 {
    247    va_list args;
    248    va_start(args, fmtString);
    249    _mesa_gl_vdebug(ctx, id, source, type, severity, fmtString, args);
    250    va_end(args);
    251 }
    252 
    253 
    254 /**
    255  * Record an OpenGL state error.  These usually occur when the user
    256  * passes invalid parameters to a GL function.
    257  *
    258  * If debugging is enabled (either at compile-time via the DEBUG macro, or
    259  * run-time via the MESA_DEBUG environment variable), report the error with
    260  * _mesa_debug().
    261  *
    262  * \param ctx the GL context.
    263  * \param error the error value.
    264  * \param fmtString printf() style format string, followed by optional args
    265  */
    266 void
    267 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
    268 {
    269    GLboolean do_output, do_log;
    270    /* Ideally this would be set up by the caller, so that we had proper IDs
    271     * per different message.
    272     */
    273    static GLuint error_msg_id = 0;
    274 
    275    _mesa_debug_get_id(&error_msg_id);
    276 
    277    do_output = should_output(ctx, error, fmtString);
    278 
    279    mtx_lock(&ctx->DebugMutex);
    280    if (ctx->Debug) {
    281       do_log = _mesa_debug_is_message_enabled(ctx->Debug,
    282                                               MESA_DEBUG_SOURCE_API,
    283                                               MESA_DEBUG_TYPE_ERROR,
    284                                               error_msg_id,
    285                                               MESA_DEBUG_SEVERITY_HIGH);
    286    }
    287    else {
    288       do_log = GL_FALSE;
    289    }
    290    mtx_unlock(&ctx->DebugMutex);
    291 
    292    if (do_output || do_log) {
    293       char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
    294       int len;
    295       va_list args;
    296 
    297       va_start(args, fmtString);
    298       len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
    299       va_end(args);
    300 
    301       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
    302          /* Too long error message. Whoever calls _mesa_error should use
    303           * shorter strings.
    304           */
    305          assert(0);
    306          return;
    307       }
    308 
    309       len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
    310                            _mesa_enum_to_string(error), s);
    311       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
    312          /* Same as above. */
    313          assert(0);
    314          return;
    315       }
    316 
    317       /* Print the error to stderr if needed. */
    318       if (do_output) {
    319          output_if_debug("Mesa: User error", s2, GL_TRUE);
    320       }
    321 
    322       /* Log the error via ARB_debug_output if needed.*/
    323       if (do_log) {
    324          _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR,
    325                        error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2);
    326       }
    327    }
    328 
    329    /* Set the GL context error state for glGetError. */
    330    _mesa_record_error(ctx, error);
    331 }
    332 
    333 void
    334 _mesa_error_no_memory(const char *caller)
    335 {
    336    GET_CURRENT_CONTEXT(ctx);
    337    _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller);
    338 }
    339 
    340 /**
    341  * Report debug information.  Print error message to stderr via fprintf().
    342  * No-op if DEBUG mode not enabled.
    343  *
    344  * \param ctx GL context.
    345  * \param fmtString printf()-style format string, followed by optional args.
    346  */
    347 void
    348 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
    349 {
    350 #ifdef DEBUG
    351    char s[MAX_DEBUG_MESSAGE_LENGTH];
    352    va_list args;
    353    va_start(args, fmtString);
    354    _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
    355    va_end(args);
    356    output_if_debug("Mesa", s, GL_FALSE);
    357 #endif /* DEBUG */
    358    (void) ctx;
    359    (void) fmtString;
    360 }
    361 
    362 
    363 void
    364 _mesa_log(const char *fmtString, ...)
    365 {
    366    char s[MAX_DEBUG_MESSAGE_LENGTH];
    367    va_list args;
    368    va_start(args, fmtString);
    369    _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
    370    va_end(args);
    371    output_if_debug("", s, GL_FALSE);
    372 }
    373 
    374 
    375 /**
    376  * Report debug information from the shader compiler via GL_ARB_debug_output.
    377  *
    378  * \param ctx GL context.
    379  * \param type The namespace to which this message belongs.
    380  * \param id The message ID within the given namespace.
    381  * \param msg The message to output. Must be null-terminated.
    382  */
    383 void
    384 _mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id,
    385                    const char *msg)
    386 {
    387    enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
    388    enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
    389    int len;
    390 
    391    _mesa_debug_get_id(id);
    392 
    393    len = strlen(msg);
    394 
    395    /* Truncate the message if necessary. */
    396    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
    397       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
    398 
    399    _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
    400 }
    401