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  * Version:  7.1
      9  *
     10  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
     11  *
     12  * Permission is hereby granted, free of charge, to any person obtaining a
     13  * copy of this software and associated documentation files (the "Software"),
     14  * to deal in the Software without restriction, including without limitation
     15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     16  * and/or sell copies of the Software, and to permit persons to whom the
     17  * Software is furnished to do so, subject to the following conditions:
     18  *
     19  * The above copyright notice and this permission notice shall be included
     20  * in all copies or substantial portions of the Software.
     21  *
     22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     25  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     26  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  */
     29 
     30 
     31 #include "errors.h"
     32 
     33 #include "imports.h"
     34 #include "context.h"
     35 #include "dispatch.h"
     36 #include "hash.h"
     37 #include "mtypes.h"
     38 #include "version.h"
     39 
     40 
     41 #define MAXSTRING MAX_DEBUG_MESSAGE_LENGTH
     42 
     43 
     44 struct gl_client_severity
     45 {
     46    struct simple_node link;
     47    GLuint ID;
     48 };
     49 
     50 static char out_of_memory[] = "Debugging error: out of memory";
     51 
     52 #define enum_is(e, kind1, kind2) \
     53    ((e) == GL_DEBUG_##kind1##_##kind2##_ARB || (e) == GL_DONT_CARE)
     54 #define severity_is(sev, kind) enum_is(sev, SEVERITY, kind)
     55 #define source_is(s, kind) enum_is(s, SOURCE, kind)
     56 #define type_is(t, kind) enum_is(t, TYPE, kind)
     57 
     58 /* Prevent define collision on Windows */
     59 #undef ERROR
     60 
     61 enum {
     62    SOURCE_APPLICATION,
     63    SOURCE_THIRD_PARTY,
     64 
     65    SOURCE_COUNT,
     66    SOURCE_ANY = -1
     67 };
     68 
     69 enum {
     70    TYPE_ERROR,
     71    TYPE_DEPRECATED,
     72    TYPE_UNDEFINED,
     73    TYPE_PORTABILITY,
     74    TYPE_PERFORMANCE,
     75    TYPE_OTHER,
     76 
     77    TYPE_COUNT,
     78    TYPE_ANY = -1
     79 };
     80 
     81 enum {
     82    SEVERITY_LOW,
     83    SEVERITY_MEDIUM,
     84    SEVERITY_HIGH,
     85 
     86    SEVERITY_COUNT,
     87    SEVERITY_ANY = -1
     88 };
     89 
     90 static int
     91 enum_to_index(GLenum e)
     92 {
     93    switch (e) {
     94    case GL_DEBUG_SOURCE_APPLICATION_ARB:
     95       return (int)SOURCE_APPLICATION;
     96    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
     97       return (int)SOURCE_THIRD_PARTY;
     98 
     99    case GL_DEBUG_TYPE_ERROR_ARB:
    100       return (int)TYPE_ERROR;
    101    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
    102       return (int)TYPE_DEPRECATED;
    103    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
    104       return (int)TYPE_UNDEFINED;
    105    case GL_DEBUG_TYPE_PERFORMANCE_ARB:
    106       return (int)TYPE_PERFORMANCE;
    107    case GL_DEBUG_TYPE_PORTABILITY_ARB:
    108       return (int)TYPE_PORTABILITY;
    109    case GL_DEBUG_TYPE_OTHER_ARB:
    110       return (int)TYPE_OTHER;
    111 
    112    case GL_DEBUG_SEVERITY_LOW_ARB:
    113       return (int)SEVERITY_LOW;
    114    case GL_DEBUG_SEVERITY_MEDIUM_ARB:
    115       return (int)SEVERITY_MEDIUM;
    116    case GL_DEBUG_SEVERITY_HIGH_ARB:
    117       return (int)SEVERITY_HIGH;
    118 
    119    case GL_DONT_CARE:
    120       return (int)TYPE_ANY;
    121 
    122    default:
    123       assert(0 && "unreachable");
    124       return -2;
    125    };
    126 }
    127 
    128 
    129 /*
    130  * We store a bitfield in the hash table, with five possible values total.
    131  *
    132  * The ENABLED_BIT's purpose is self-explanatory.
    133  *
    134  * The FOUND_BIT is needed to differentiate the value of DISABLED from
    135  * the value returned by HashTableLookup() when it can't find the given key.
    136  *
    137  * The KNOWN_SEVERITY bit is a bit complicated:
    138  *
    139  * A client may call Control() with an array of IDs, then call Control()
    140  * on all message IDs of a certain severity, then Insert() one of the
    141  * previously specified IDs, giving us a known severity level, then call
    142  * Control() on all message IDs of a certain severity level again.
    143  *
    144  * After the first call, those IDs will have a FOUND_BIT, but will not
    145  * exist in any severity-specific list, so the second call will not
    146  * impact them. This is undesirable but unavoidable given the API:
    147  * The only entrypoint that gives a severity for a client-defined ID
    148  * is the Insert() call.
    149  *
    150  * For the sake of Control(), we want to maintain the invariant
    151  * that an ID will either appear in none of the three severity lists,
    152  * or appear once, to minimize pointless duplication and potential surprises.
    153  *
    154  * Because Insert() is the only place that will learn an ID's severity,
    155  * it should insert an ID into the appropriate list, but only if the ID
    156  * doesn't exist in it or any other list yet. Because searching all three
    157  * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
    158  */
    159 enum {
    160    FOUND_BIT = 1 << 0,
    161    ENABLED_BIT = 1 << 1,
    162    KNOWN_SEVERITY = 1 << 2,
    163 
    164    /* HashTable reserves zero as a return value meaning 'not found' */
    165    NOT_FOUND = 0,
    166    DISABLED = FOUND_BIT,
    167    ENABLED = ENABLED_BIT | FOUND_BIT
    168 };
    169 
    170 /**
    171  * Returns the state of the given message ID in a client-controlled
    172  * namespace.
    173  * 'source', 'type', and 'severity' are array indices like TYPE_ERROR,
    174  * not GL enums.
    175  */
    176 static GLboolean
    177 get_message_state(struct gl_context *ctx, int source, int type,
    178                   GLuint id, int severity)
    179 {
    180    struct gl_client_namespace *nspace =
    181          &ctx->Debug.ClientIDs.Namespaces[source][type];
    182    uintptr_t state;
    183 
    184    /* In addition to not being able to store zero as a value, HashTable also
    185       can't use zero as a key. */
    186    if (id)
    187       state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
    188    else
    189       state = nspace->ZeroID;
    190 
    191    /* Only do this once for each ID. This makes sure the ID exists in,
    192       at most, one list, and does not pointlessly appear multiple times. */
    193    if (!(state & KNOWN_SEVERITY)) {
    194       struct gl_client_severity *entry;
    195 
    196       if (state == NOT_FOUND) {
    197          if (ctx->Debug.ClientIDs.Defaults[severity][source][type])
    198             state = ENABLED;
    199          else
    200             state = DISABLED;
    201       }
    202 
    203       entry = malloc(sizeof *entry);
    204       if (!entry)
    205          goto out;
    206 
    207       state |= KNOWN_SEVERITY;
    208 
    209       if (id)
    210          _mesa_HashInsert(nspace->IDs, id, (void*)state);
    211       else
    212          nspace->ZeroID = state;
    213 
    214       entry->ID = id;
    215       insert_at_tail(&nspace->Severity[severity], &entry->link);
    216    }
    217 
    218 out:
    219    return !!(state & ENABLED_BIT);
    220 }
    221 
    222 /**
    223  * Sets the state of the given message ID in a client-controlled
    224  * namespace.
    225  * 'source' and 'type' are array indices like TYPE_ERROR, not GL enums.
    226  */
    227 static void
    228 set_message_state(struct gl_context *ctx, int source, int type,
    229                   GLuint id, GLboolean enabled)
    230 {
    231    struct gl_client_namespace *nspace =
    232          &ctx->Debug.ClientIDs.Namespaces[source][type];
    233    uintptr_t state;
    234 
    235    /* In addition to not being able to store zero as a value, HashTable also
    236       can't use zero as a key. */
    237    if (id)
    238       state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
    239    else
    240       state = nspace->ZeroID;
    241 
    242    if (state == NOT_FOUND)
    243       state = enabled ? ENABLED : DISABLED;
    244    else {
    245       if (enabled)
    246          state |= ENABLED_BIT;
    247       else
    248          state &= ~ENABLED_BIT;
    249    }
    250 
    251    if (id)
    252       _mesa_HashInsert(nspace->IDs, id, (void*)state);
    253    else
    254       nspace->ZeroID = state;
    255 }
    256 
    257 /**
    258  * Whether a debugging message should be logged or not.
    259  * For implementation-controlled namespaces, we keep an array
    260  * of booleans per namespace, per context, recording whether
    261  * each individual message is enabled or not. The message ID
    262  * is an index into the namespace's array.
    263  */
    264 static GLboolean
    265 should_log(struct gl_context *ctx, GLenum source, GLenum type,
    266            GLuint id, GLenum severity)
    267 {
    268    if (source == GL_DEBUG_SOURCE_APPLICATION_ARB ||
    269        source == GL_DEBUG_SOURCE_THIRD_PARTY_ARB) {
    270       int s, t, sev;
    271       s = enum_to_index(source);
    272       t = enum_to_index(type);
    273       sev = enum_to_index(severity);
    274 
    275       return get_message_state(ctx, s, t, sev, id);
    276    }
    277 
    278    if (type_is(type, ERROR)) {
    279       if (source_is(source, API))
    280          return ctx->Debug.ApiErrors[id];
    281       if (source_is(source, WINDOW_SYSTEM))
    282          return ctx->Debug.WinsysErrors[id];
    283       if (source_is(source, SHADER_COMPILER))
    284          return ctx->Debug.ShaderErrors[id];
    285       if (source_is(source, OTHER))
    286          return ctx->Debug.OtherErrors[id];
    287    }
    288 
    289    return (severity != GL_DEBUG_SEVERITY_LOW_ARB);
    290 }
    291 
    292 /**
    293  * 'buf' is not necessarily a null-terminated string. When logging, copy
    294  * 'len' characters from it, store them in a new, null-terminated string,
    295  * and remember the number of bytes used by that string, *including*
    296  * the null terminator this time.
    297  */
    298 static void
    299 _mesa_log_msg(struct gl_context *ctx, GLenum source, GLenum type,
    300               GLuint id, GLenum severity, GLint len, const char *buf)
    301 {
    302    GLint nextEmpty;
    303    struct gl_debug_msg *emptySlot;
    304 
    305    assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH);
    306 
    307    if (!should_log(ctx, source, type, id, severity))
    308       return;
    309 
    310    if (ctx->Debug.Callback) {
    311       ctx->Debug.Callback(source, type, id, severity,
    312                           len, buf, ctx->Debug.CallbackData);
    313       return;
    314    }
    315 
    316    if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
    317       return;
    318 
    319    nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages)
    320                           % MAX_DEBUG_LOGGED_MESSAGES;
    321    emptySlot = &ctx->Debug.Log[nextEmpty];
    322 
    323    assert(!emptySlot->message && !emptySlot->length);
    324 
    325    emptySlot->message = MALLOC(len+1);
    326    if (emptySlot->message) {
    327       (void) strncpy(emptySlot->message, buf, (size_t)len);
    328       emptySlot->message[len] = '\0';
    329 
    330       emptySlot->length = len+1;
    331       emptySlot->source = source;
    332       emptySlot->type = type;
    333       emptySlot->id = id;
    334       emptySlot->severity = severity;
    335    } else {
    336       /* malloc failed! */
    337       emptySlot->message = out_of_memory;
    338       emptySlot->length = strlen(out_of_memory)+1;
    339       emptySlot->source = GL_DEBUG_SOURCE_OTHER_ARB;
    340       emptySlot->type = GL_DEBUG_TYPE_ERROR_ARB;
    341       emptySlot->id = OTHER_ERROR_OUT_OF_MEMORY;
    342       emptySlot->severity = GL_DEBUG_SEVERITY_HIGH_ARB;
    343    }
    344 
    345    if (ctx->Debug.NumMessages == 0)
    346       ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
    347 
    348    ctx->Debug.NumMessages++;
    349 }
    350 
    351 /**
    352  * Pop the oldest debug message out of the log.
    353  * Writes the message string, including the null terminator, into 'buf',
    354  * using up to 'bufSize' bytes. If 'bufSize' is too small, or
    355  * if 'buf' is NULL, nothing is written.
    356  *
    357  * Returns the number of bytes written on success, or when 'buf' is NULL,
    358  * the number that would have been written. A return value of 0
    359  * indicates failure.
    360  */
    361 static GLsizei
    362 _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
    363               GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
    364 {
    365    struct gl_debug_msg *msg;
    366    GLsizei length;
    367 
    368    if (ctx->Debug.NumMessages == 0)
    369       return 0;
    370 
    371    msg = &ctx->Debug.Log[ctx->Debug.NextMsg];
    372    length = msg->length;
    373 
    374    assert(length > 0 && length == ctx->Debug.NextMsgLength);
    375 
    376    if (bufSize < length && buf != NULL)
    377       return 0;
    378 
    379    if (severity)
    380       *severity = msg->severity;
    381    if (source)
    382       *source = msg->source;
    383    if (type)
    384       *type = msg->type;
    385    if (id)
    386       *id = msg->id;
    387 
    388    if (buf) {
    389       assert(msg->message[length-1] == '\0');
    390       (void) strncpy(buf, msg->message, (size_t)length);
    391    }
    392 
    393    if (msg->message != (char*)out_of_memory)
    394       FREE(msg->message);
    395    msg->message = NULL;
    396    msg->length = 0;
    397 
    398    ctx->Debug.NumMessages--;
    399    ctx->Debug.NextMsg++;
    400    ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
    401    ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
    402 
    403    return length;
    404 }
    405 
    406 /**
    407  * Verify that source, type, and severity are valid enums.
    408  * glDebugMessageInsertARB only accepts two values for 'source',
    409  * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
    410  * in any parameter, so handle those cases specially.
    411  */
    412 static GLboolean
    413 validate_params(struct gl_context *ctx, unsigned caller,
    414                 GLenum source, GLenum type, GLenum severity)
    415 {
    416 #define INSERT 1
    417 #define CONTROL 2
    418    switch(source) {
    419    case GL_DEBUG_SOURCE_APPLICATION_ARB:
    420    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
    421       break;
    422    case GL_DEBUG_SOURCE_API_ARB:
    423    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
    424    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
    425    case GL_DEBUG_SOURCE_OTHER_ARB:
    426       if (caller != INSERT)
    427          break;
    428    case GL_DONT_CARE:
    429       if (caller == CONTROL)
    430          break;
    431    default:
    432       goto error;
    433    }
    434 
    435    switch(type) {
    436    case GL_DEBUG_TYPE_ERROR_ARB:
    437    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
    438    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
    439    case GL_DEBUG_TYPE_PERFORMANCE_ARB:
    440    case GL_DEBUG_TYPE_PORTABILITY_ARB:
    441    case GL_DEBUG_TYPE_OTHER_ARB:
    442       break;
    443    case GL_DONT_CARE:
    444       if (caller == CONTROL)
    445          break;
    446    default:
    447       goto error;
    448    }
    449 
    450    switch(severity) {
    451    case GL_DEBUG_SEVERITY_HIGH_ARB:
    452    case GL_DEBUG_SEVERITY_MEDIUM_ARB:
    453    case GL_DEBUG_SEVERITY_LOW_ARB:
    454       break;
    455    case GL_DONT_CARE:
    456       if (caller == CONTROL)
    457          break;
    458    default:
    459       goto error;
    460    }
    461    return GL_TRUE;
    462 
    463 error:
    464    {
    465       const char *callerstr;
    466       if (caller == INSERT)
    467          callerstr = "glDebugMessageInsertARB";
    468       else if (caller == CONTROL)
    469          callerstr = "glDebugMessageControlARB";
    470       else
    471          return GL_FALSE;
    472 
    473       _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s"
    474                   "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
    475                   source, type, severity);
    476    }
    477    return GL_FALSE;
    478 }
    479 
    480 static void GLAPIENTRY
    481 _mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
    482                             GLenum severity, GLint length,
    483                             const GLcharARB* buf)
    484 {
    485    GET_CURRENT_CONTEXT(ctx);
    486 
    487    if (!validate_params(ctx, INSERT, source, type, severity))
    488       return; /* GL_INVALID_ENUM */
    489 
    490    if (length < 0)
    491       length = strlen(buf);
    492 
    493    if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
    494       _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB"
    495                  "(length=%d, which is not less than "
    496                  "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length,
    497                  MAX_DEBUG_MESSAGE_LENGTH);
    498       return;
    499    }
    500 
    501    _mesa_log_msg(ctx, source, type, id, severity, length, buf);
    502 }
    503 
    504 static GLuint GLAPIENTRY
    505 _mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
    506                             GLenum* types, GLenum* ids, GLenum* severities,
    507                             GLsizei* lengths, GLcharARB* messageLog)
    508 {
    509    GET_CURRENT_CONTEXT(ctx);
    510    GLuint ret;
    511 
    512    if (!messageLog)
    513       logSize = 0;
    514 
    515    if (logSize < 0) {
    516       _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB"
    517                  "(logSize=%d : logSize must not be negative)", logSize);
    518       return 0;
    519    }
    520 
    521    for (ret = 0; ret < count; ret++) {
    522       GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
    523                                       logSize, messageLog);
    524       if (!written)
    525          break;
    526 
    527       if (messageLog) {
    528          messageLog += written;
    529          logSize -= written;
    530       }
    531       if (lengths) {
    532          *lengths = written;
    533          lengths++;
    534       }
    535 
    536       if (severities)
    537          severities++;
    538       if (sources)
    539          sources++;
    540       if (types)
    541          types++;
    542       if (ids)
    543          ids++;
    544    }
    545 
    546    return ret;
    547 }
    548 
    549 /**
    550  * 'array' is an array representing a particular debugging-message namespace.
    551  * I.e., the set of all API errors, or the set of all Shader Compiler errors.
    552  * 'size' is the size of 'array'. 'count' is the size of 'ids', an array
    553  * of indices into 'array'. All the elements of 'array' at the indices
    554  * listed in 'ids' will be overwritten with the value of 'enabled'.
    555  *
    556  * If 'count' is zero, all elements in 'array' are overwritten with the
    557  * value of 'enabled'.
    558  */
    559 static void
    560 control_messages(GLboolean *array, GLuint size,
    561                  GLsizei count, const GLuint *ids, GLboolean enabled)
    562 {
    563    GLsizei i;
    564 
    565    if (!count) {
    566       GLuint id;
    567       for (id = 0; id < size; id++) {
    568          array[id] = enabled;
    569       }
    570       return;
    571    }
    572 
    573    for (i = 0; i < count; i++) {
    574       if (ids[i] >= size) {
    575          /* XXX: The spec doesn't say what to do with a non-existent ID. */
    576          continue;
    577       }
    578       array[ids[i]] = enabled;
    579    }
    580 }
    581 
    582 /**
    583  * Set the state of all message IDs found in the given intersection
    584  * of 'source', 'type', and 'severity'. Note that all three of these
    585  * parameters are array indices, not the corresponding GL enums.
    586  *
    587  * This requires both setting the state of all previously seen message
    588  * IDs in the hash table, and setting the default state for all
    589  * applicable combinations of source/type/severity, so that all the
    590  * yet-unknown message IDs that may be used in the future will be
    591  * impacted as if they were already known.
    592  */
    593 static void
    594 control_app_messages_by_group(struct gl_context *ctx, int source, int type,
    595                               int severity, GLboolean enabled)
    596 {
    597    struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
    598    int s, t, sev, smax, tmax, sevmax;
    599 
    600    if (source == SOURCE_ANY) {
    601       source = 0;
    602       smax = SOURCE_COUNT;
    603    } else {
    604       smax = source+1;
    605    }
    606 
    607    if (type == TYPE_ANY) {
    608       type = 0;
    609       tmax = TYPE_COUNT;
    610    } else {
    611       tmax = type+1;
    612    }
    613 
    614    if (severity == SEVERITY_ANY) {
    615       severity = 0;
    616       sevmax = SEVERITY_COUNT;
    617    } else {
    618       sevmax = severity+1;
    619    }
    620 
    621    for (sev = severity; sev < sevmax; sev++)
    622       for (s = source; s < smax; s++)
    623          for (t = type; t < tmax; t++) {
    624             struct simple_node *node;
    625             struct gl_client_severity *entry;
    626 
    627             /* change the default for IDs we've never seen before. */
    628             ClientIDs->Defaults[sev][s][t] = enabled;
    629 
    630             /* Now change the state of IDs we *have* seen... */
    631             foreach(node, &ClientIDs->Namespaces[s][t].Severity[sev]) {
    632                entry = (struct gl_client_severity *)node;
    633                set_message_state(ctx, s, t, entry->ID, enabled);
    634             }
    635          }
    636 }
    637 
    638 /**
    639  * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
    640  * require special handling, since the IDs in them are controlled by clients,
    641  * not the OpenGL implementation.
    642  *
    643  * 'count' is the length of the array 'ids'. If 'count' is nonzero, all
    644  * the given IDs in the namespace defined by 'esource' and 'etype'
    645  * will be affected.
    646  *
    647  * If 'count' is zero, this sets the state of all IDs that match
    648  * the combination of 'esource', 'etype', and 'eseverity'.
    649  */
    650 static void
    651 control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
    652                      GLenum eseverity, GLsizei count, const GLuint *ids,
    653                      GLboolean enabled)
    654 {
    655    int source, type, severity;
    656    GLsizei i;
    657 
    658    source = enum_to_index(esource);
    659    type = enum_to_index(etype);
    660    severity = enum_to_index(eseverity);
    661 
    662    if (count)
    663       assert(severity == SEVERITY_ANY && type != TYPE_ANY
    664              && source != SOURCE_ANY);
    665 
    666    for (i = 0; i < count; i++)
    667       set_message_state(ctx, source, type, ids[i], enabled);
    668 
    669    if (count)
    670       return;
    671 
    672    control_app_messages_by_group(ctx, source, type, severity, enabled);
    673 }
    674 
    675 static void GLAPIENTRY
    676 _mesa_DebugMessageControlARB(GLenum source, GLenum type, GLenum severity,
    677                              GLsizei count, const GLuint *ids,
    678                              GLboolean enabled)
    679 {
    680    GET_CURRENT_CONTEXT(ctx);
    681 
    682    if (count < 0) {
    683       _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageControlARB"
    684                  "(count=%d : count must not be negative)", count);
    685       return;
    686    }
    687 
    688    if (!validate_params(ctx, CONTROL, source, type, severity))
    689       return; /* GL_INVALID_ENUM */
    690 
    691    if (count && (severity != GL_DONT_CARE || type == GL_DONT_CARE
    692                  || source == GL_DONT_CARE)) {
    693       _mesa_error(ctx, GL_INVALID_OPERATION, "glDebugMessageControlARB"
    694                  "(When passing an array of ids, severity must be"
    695          " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.");
    696       return;
    697    }
    698 
    699    if (source_is(source, APPLICATION) || source_is(source, THIRD_PARTY))
    700       control_app_messages(ctx, source, type, severity, count, ids, enabled);
    701 
    702    if (severity_is(severity, HIGH)) {
    703       if (type_is(type, ERROR)) {
    704          if (source_is(source, API))
    705             control_messages(ctx->Debug.ApiErrors, API_ERROR_COUNT,
    706                              count, ids, enabled);
    707          if (source_is(source, WINDOW_SYSTEM))
    708             control_messages(ctx->Debug.WinsysErrors, WINSYS_ERROR_COUNT,
    709                              count, ids, enabled);
    710          if (source_is(source, SHADER_COMPILER))
    711             control_messages(ctx->Debug.ShaderErrors, SHADER_ERROR_COUNT,
    712                              count, ids, enabled);
    713          if (source_is(source, OTHER))
    714             control_messages(ctx->Debug.OtherErrors, OTHER_ERROR_COUNT,
    715                              count, ids, enabled);
    716       }
    717    }
    718 }
    719 
    720 static void GLAPIENTRY
    721 _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const GLvoid *userParam)
    722 {
    723    GET_CURRENT_CONTEXT(ctx);
    724    ctx->Debug.Callback = callback;
    725    ctx->Debug.CallbackData = (void *) userParam;
    726 }
    727 
    728 void
    729 _mesa_init_errors_dispatch(struct _glapi_table *disp)
    730 {
    731    SET_DebugMessageCallbackARB(disp, _mesa_DebugMessageCallbackARB);
    732    SET_DebugMessageControlARB(disp, _mesa_DebugMessageControlARB);
    733    SET_DebugMessageInsertARB(disp, _mesa_DebugMessageInsertARB);
    734    SET_GetDebugMessageLogARB(disp, _mesa_GetDebugMessageLogARB);
    735 }
    736 
    737 void
    738 _mesa_init_errors(struct gl_context *ctx)
    739 {
    740    int s, t, sev;
    741    struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
    742 
    743    ctx->Debug.Callback = NULL;
    744    ctx->Debug.SyncOutput = GL_FALSE;
    745    ctx->Debug.Log[0].length = 0;
    746    ctx->Debug.NumMessages = 0;
    747    ctx->Debug.NextMsg = 0;
    748    ctx->Debug.NextMsgLength = 0;
    749 
    750    /* Enable all the messages with severity HIGH or MEDIUM by default. */
    751    memset(ctx->Debug.ApiErrors, GL_TRUE, sizeof ctx->Debug.ApiErrors);
    752    memset(ctx->Debug.WinsysErrors, GL_TRUE, sizeof ctx->Debug.WinsysErrors);
    753    memset(ctx->Debug.ShaderErrors, GL_TRUE, sizeof ctx->Debug.ShaderErrors);
    754    memset(ctx->Debug.OtherErrors, GL_TRUE, sizeof ctx->Debug.OtherErrors);
    755    memset(ClientIDs->Defaults[SEVERITY_HIGH], GL_TRUE,
    756           sizeof ClientIDs->Defaults[SEVERITY_HIGH]);
    757    memset(ClientIDs->Defaults[SEVERITY_MEDIUM], GL_TRUE,
    758           sizeof ClientIDs->Defaults[SEVERITY_MEDIUM]);
    759    memset(ClientIDs->Defaults[SEVERITY_LOW], GL_FALSE,
    760           sizeof ClientIDs->Defaults[SEVERITY_LOW]);
    761 
    762    /* Initialize state for filtering client-provided debug messages. */
    763    for (s = 0; s < SOURCE_COUNT; s++)
    764       for (t = 0; t < TYPE_COUNT; t++) {
    765          ClientIDs->Namespaces[s][t].IDs = _mesa_NewHashTable();
    766          assert(ClientIDs->Namespaces[s][t].IDs);
    767 
    768          for (sev = 0; sev < SEVERITY_COUNT; sev++)
    769             make_empty_list(&ClientIDs->Namespaces[s][t].Severity[sev]);
    770       }
    771 }
    772 
    773 void
    774 _mesa_free_errors_data(struct gl_context *ctx)
    775 {
    776    int s, t, sev;
    777    struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
    778 
    779    /* Tear down state for filtering client-provided debug messages. */
    780    for (s = 0; s < SOURCE_COUNT; s++)
    781       for (t = 0; t < TYPE_COUNT; t++) {
    782          _mesa_DeleteHashTable(ClientIDs->Namespaces[s][t].IDs);
    783          for (sev = 0; sev < SEVERITY_COUNT; sev++) {
    784             struct simple_node *node, *tmp;
    785             struct gl_client_severity *entry;
    786 
    787             foreach_s(node, tmp, &ClientIDs->Namespaces[s][t].Severity[sev]) {
    788                entry = (struct gl_client_severity *)node;
    789                FREE(entry);
    790             }
    791          }
    792       }
    793 }
    794 
    795 /**********************************************************************/
    796 /** \name Diagnostics */
    797 /*@{*/
    798 
    799 static void
    800 output_if_debug(const char *prefixString, const char *outputString,
    801                 GLboolean newline)
    802 {
    803    static int debug = -1;
    804    static FILE *fout = NULL;
    805 
    806    /* Init the local 'debug' var once.
    807     * Note: the _mesa_init_debug() function should have been called
    808     * by now so MESA_DEBUG_FLAGS will be initialized.
    809     */
    810    if (debug == -1) {
    811       /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
    812        * etc to the named file.  Otherwise, output to stderr.
    813        */
    814       const char *logFile = _mesa_getenv("MESA_LOG_FILE");
    815       if (logFile)
    816          fout = fopen(logFile, "w");
    817       if (!fout)
    818          fout = stderr;
    819 #ifdef DEBUG
    820       /* in debug builds, print messages unless MESA_DEBUG="silent" */
    821       if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
    822          debug = 0;
    823       else
    824          debug = 1;
    825 #else
    826       /* in release builds, be silent unless MESA_DEBUG is set */
    827       debug = _mesa_getenv("MESA_DEBUG") != NULL;
    828 #endif
    829    }
    830 
    831    /* Now only print the string if we're required to do so. */
    832    if (debug) {
    833       fprintf(fout, "%s: %s", prefixString, outputString);
    834       if (newline)
    835          fprintf(fout, "\n");
    836       fflush(fout);
    837 
    838 #if defined(_WIN32) && !defined(_WIN32_WCE)
    839       /* stderr from windows applications without console is not usually
    840        * visible, so communicate with the debugger instead */
    841       {
    842          char buf[4096];
    843          _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
    844          OutputDebugStringA(buf);
    845       }
    846 #endif
    847    }
    848 }
    849 
    850 
    851 /**
    852  * Return string version of GL error code.
    853  */
    854 static const char *
    855 error_string( GLenum error )
    856 {
    857    switch (error) {
    858    case GL_NO_ERROR:
    859       return "GL_NO_ERROR";
    860    case GL_INVALID_VALUE:
    861       return "GL_INVALID_VALUE";
    862    case GL_INVALID_ENUM:
    863       return "GL_INVALID_ENUM";
    864    case GL_INVALID_OPERATION:
    865       return "GL_INVALID_OPERATION";
    866    case GL_STACK_OVERFLOW:
    867       return "GL_STACK_OVERFLOW";
    868    case GL_STACK_UNDERFLOW:
    869       return "GL_STACK_UNDERFLOW";
    870    case GL_OUT_OF_MEMORY:
    871       return "GL_OUT_OF_MEMORY";
    872    case GL_TABLE_TOO_LARGE:
    873       return "GL_TABLE_TOO_LARGE";
    874    case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
    875       return "GL_INVALID_FRAMEBUFFER_OPERATION";
    876    default:
    877       return "unknown";
    878    }
    879 }
    880 
    881 
    882 /**
    883  * When a new type of error is recorded, print a message describing
    884  * previous errors which were accumulated.
    885  */
    886 static void
    887 flush_delayed_errors( struct gl_context *ctx )
    888 {
    889    char s[MAXSTRING];
    890 
    891    if (ctx->ErrorDebugCount) {
    892       _mesa_snprintf(s, MAXSTRING, "%d similar %s errors",
    893                      ctx->ErrorDebugCount,
    894                      error_string(ctx->ErrorValue));
    895 
    896       output_if_debug("Mesa", s, GL_TRUE);
    897 
    898       ctx->ErrorDebugCount = 0;
    899    }
    900 }
    901 
    902 
    903 /**
    904  * Report a warning (a recoverable error condition) to stderr if
    905  * either DEBUG is defined or the MESA_DEBUG env var is set.
    906  *
    907  * \param ctx GL context.
    908  * \param fmtString printf()-like format string.
    909  */
    910 void
    911 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
    912 {
    913    char str[MAXSTRING];
    914    va_list args;
    915    va_start( args, fmtString );
    916    (void) _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
    917    va_end( args );
    918 
    919    if (ctx)
    920       flush_delayed_errors( ctx );
    921 
    922    output_if_debug("Mesa warning", str, GL_TRUE);
    923 }
    924 
    925 
    926 /**
    927  * Report an internal implementation problem.
    928  * Prints the message to stderr via fprintf().
    929  *
    930  * \param ctx GL context.
    931  * \param fmtString problem description string.
    932  */
    933 void
    934 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
    935 {
    936    va_list args;
    937    char str[MAXSTRING];
    938    static int numCalls = 0;
    939 
    940    (void) ctx;
    941 
    942    if (numCalls < 50) {
    943       numCalls++;
    944 
    945       va_start( args, fmtString );
    946       _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
    947       va_end( args );
    948       fprintf(stderr, "Mesa %s implementation error: %s\n",
    949               MESA_VERSION_STRING, str);
    950       fprintf(stderr, "Please report at bugs.freedesktop.org\n");
    951    }
    952 }
    953 
    954 static GLboolean
    955 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
    956 {
    957    static GLint debug = -1;
    958 
    959    /* Check debug environment variable only once:
    960     */
    961    if (debug == -1) {
    962       const char *debugEnv = _mesa_getenv("MESA_DEBUG");
    963 
    964 #ifdef DEBUG
    965       if (debugEnv && strstr(debugEnv, "silent"))
    966          debug = GL_FALSE;
    967       else
    968          debug = GL_TRUE;
    969 #else
    970       if (debugEnv)
    971          debug = GL_TRUE;
    972       else
    973          debug = GL_FALSE;
    974 #endif
    975    }
    976 
    977    if (debug) {
    978       if (ctx->ErrorValue != error ||
    979           ctx->ErrorDebugFmtString != fmtString) {
    980          flush_delayed_errors( ctx );
    981          ctx->ErrorDebugFmtString = fmtString;
    982          ctx->ErrorDebugCount = 0;
    983          return GL_TRUE;
    984       }
    985       ctx->ErrorDebugCount++;
    986    }
    987    return GL_FALSE;
    988 }
    989 
    990 
    991 /**
    992  * Record an OpenGL state error.  These usually occur when the user
    993  * passes invalid parameters to a GL function.
    994  *
    995  * If debugging is enabled (either at compile-time via the DEBUG macro, or
    996  * run-time via the MESA_DEBUG environment variable), report the error with
    997  * _mesa_debug().
    998  *
    999  * \param ctx the GL context.
   1000  * \param error the error value.
   1001  * \param fmtString printf() style format string, followed by optional args
   1002  */
   1003 void
   1004 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
   1005 {
   1006    GLboolean do_output, do_log;
   1007 
   1008    do_output = should_output(ctx, error, fmtString);
   1009    do_log = should_log(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB,
   1010                        API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB);
   1011 
   1012    if (do_output || do_log) {
   1013       char s[MAXSTRING], s2[MAXSTRING];
   1014       int len;
   1015       va_list args;
   1016 
   1017       va_start(args, fmtString);
   1018       len = _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
   1019       va_end(args);
   1020 
   1021       if (len >= MAXSTRING) {
   1022          /* Too long error message. Whoever calls _mesa_error should use
   1023           * shorter strings. */
   1024          ASSERT(0);
   1025          return;
   1026       }
   1027 
   1028       len = _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s);
   1029       if (len >= MAXSTRING) {
   1030          /* Same as above. */
   1031          ASSERT(0);
   1032          return;
   1033       }
   1034 
   1035       /* Print the error to stderr if needed. */
   1036       if (do_output) {
   1037          output_if_debug("Mesa: User error", s2, GL_TRUE);
   1038       }
   1039 
   1040       /* Log the error via ARB_debug_output if needed.*/
   1041       if (do_log) {
   1042          _mesa_log_msg(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB,
   1043                        API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB, len, s2);
   1044       }
   1045    }
   1046 
   1047    /* Set the GL context error state for glGetError. */
   1048    _mesa_record_error(ctx, error);
   1049 }
   1050 
   1051 
   1052 /**
   1053  * Report debug information.  Print error message to stderr via fprintf().
   1054  * No-op if DEBUG mode not enabled.
   1055  *
   1056  * \param ctx GL context.
   1057  * \param fmtString printf()-style format string, followed by optional args.
   1058  */
   1059 void
   1060 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
   1061 {
   1062 #ifdef DEBUG
   1063    char s[MAXSTRING];
   1064    va_list args;
   1065    va_start(args, fmtString);
   1066    _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
   1067    va_end(args);
   1068    output_if_debug("Mesa", s, GL_FALSE);
   1069 #endif /* DEBUG */
   1070    (void) ctx;
   1071    (void) fmtString;
   1072 }
   1073 
   1074 
   1075 /**
   1076  * Report debug information from the shader compiler via GL_ARB_debug_output.
   1077  *
   1078  * \param ctx GL context.
   1079  * \param type The namespace to which this message belongs.
   1080  * \param id The message ID within the given namespace.
   1081  * \param msg The message to output. Need not be null-terminated.
   1082  * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
   1083  */
   1084 void
   1085 _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint id,
   1086                     const char *msg, int len )
   1087 {
   1088    GLenum source = GL_DEBUG_SOURCE_SHADER_COMPILER_ARB,
   1089           severity;
   1090 
   1091    switch (type) {
   1092    case GL_DEBUG_TYPE_ERROR_ARB:
   1093       assert(id < SHADER_ERROR_COUNT);
   1094       severity = GL_DEBUG_SEVERITY_HIGH_ARB;
   1095       break;
   1096    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
   1097    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
   1098    case GL_DEBUG_TYPE_PORTABILITY_ARB:
   1099    case GL_DEBUG_TYPE_PERFORMANCE_ARB:
   1100    case GL_DEBUG_TYPE_OTHER_ARB:
   1101       assert(0 && "other categories not implemented yet");
   1102    default:
   1103       _mesa_problem(ctx, "bad enum in _mesa_shader_debug()");
   1104       return;
   1105    }
   1106 
   1107    if (len < 0)
   1108       len = strlen(msg);
   1109 
   1110    /* Truncate the message if necessary. */
   1111    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
   1112       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
   1113 
   1114    _mesa_log_msg(ctx, source, type, id, severity, len, msg);
   1115 }
   1116 
   1117 /*@}*/
   1118