Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 "errors.h"
  32. #include "enums.h"
  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. #include "hash_table.h"
  40. #include "glapi/glthread.h"
  41.  
  42. _glthread_DECLARE_STATIC_MUTEX(DynamicIDMutex);
  43. static GLuint NextDynamicID = 1;
  44.  
  45. struct gl_debug_severity
  46. {
  47.    struct simple_node link;
  48.    GLuint ID;
  49. };
  50.  
  51. static char out_of_memory[] = "Debugging error: out of memory";
  52.  
  53. static const GLenum debug_source_enums[] = {
  54.    GL_DEBUG_SOURCE_API,
  55.    GL_DEBUG_SOURCE_WINDOW_SYSTEM,
  56.    GL_DEBUG_SOURCE_SHADER_COMPILER,
  57.    GL_DEBUG_SOURCE_THIRD_PARTY,
  58.    GL_DEBUG_SOURCE_APPLICATION,
  59.    GL_DEBUG_SOURCE_OTHER,
  60. };
  61.  
  62. static const GLenum debug_type_enums[] = {
  63.    GL_DEBUG_TYPE_ERROR,
  64.    GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
  65.    GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
  66.    GL_DEBUG_TYPE_PORTABILITY,
  67.    GL_DEBUG_TYPE_PERFORMANCE,
  68.    GL_DEBUG_TYPE_OTHER,
  69. };
  70.  
  71. static const GLenum debug_severity_enums[] = {
  72.    GL_DEBUG_SEVERITY_LOW,
  73.    GL_DEBUG_SEVERITY_MEDIUM,
  74.    GL_DEBUG_SEVERITY_HIGH,
  75. };
  76.  
  77. static enum mesa_debug_source
  78. gl_enum_to_debug_source(GLenum e)
  79. {
  80.    int i;
  81.  
  82.    for (i = 0; i < Elements(debug_source_enums); i++) {
  83.       if (debug_source_enums[i] == e)
  84.          break;
  85.    }
  86.    return i;
  87. }
  88.  
  89. static enum mesa_debug_type
  90. gl_enum_to_debug_type(GLenum e)
  91. {
  92.    int i;
  93.  
  94.    for (i = 0; i < Elements(debug_type_enums); i++) {
  95.       if (debug_type_enums[i] == e)
  96.          break;
  97.    }
  98.    return i;
  99. }
  100.  
  101. static enum mesa_debug_severity
  102. gl_enum_to_debug_severity(GLenum e)
  103. {
  104.    int i;
  105.  
  106.    for (i = 0; i < Elements(debug_severity_enums); i++) {
  107.       if (debug_severity_enums[i] == e)
  108.          break;
  109.    }
  110.    return i;
  111. }
  112.  
  113. /**
  114.  * Handles generating a GL_ARB_debug_output message ID generated by the GL or
  115.  * GLSL compiler.
  116.  *
  117.  * The GL API has this "ID" mechanism, where the intention is to allow a
  118.  * client to filter in/out messages based on source, type, and ID.  Of course,
  119.  * building a giant enum list of all debug output messages that Mesa might
  120.  * generate is ridiculous, so instead we have our caller pass us a pointer to
  121.  * static storage where the ID should get stored.  This ID will be shared
  122.  * across all contexts for that message (which seems like a desirable
  123.  * property, even if it's not expected by the spec), but note that it won't be
  124.  * the same between executions if messages aren't generated in the same order.
  125.  */
  126. static void
  127. debug_get_id(GLuint *id)
  128. {
  129.    if (!(*id)) {
  130.       _glthread_LOCK_MUTEX(DynamicIDMutex);
  131.       if (!(*id))
  132.          *id = NextDynamicID++;
  133.       _glthread_UNLOCK_MUTEX(DynamicIDMutex);
  134.    }
  135. }
  136.  
  137. /*
  138.  * We store a bitfield in the hash table, with five possible values total.
  139.  *
  140.  * The ENABLED_BIT's purpose is self-explanatory.
  141.  *
  142.  * The FOUND_BIT is needed to differentiate the value of DISABLED from
  143.  * the value returned by HashTableLookup() when it can't find the given key.
  144.  *
  145.  * The KNOWN_SEVERITY bit is a bit complicated:
  146.  *
  147.  * A client may call Control() with an array of IDs, then call Control()
  148.  * on all message IDs of a certain severity, then Insert() one of the
  149.  * previously specified IDs, giving us a known severity level, then call
  150.  * Control() on all message IDs of a certain severity level again.
  151.  *
  152.  * After the first call, those IDs will have a FOUND_BIT, but will not
  153.  * exist in any severity-specific list, so the second call will not
  154.  * impact them. This is undesirable but unavoidable given the API:
  155.  * The only entrypoint that gives a severity for a client-defined ID
  156.  * is the Insert() call.
  157.  *
  158.  * For the sake of Control(), we want to maintain the invariant
  159.  * that an ID will either appear in none of the three severity lists,
  160.  * or appear once, to minimize pointless duplication and potential surprises.
  161.  *
  162.  * Because Insert() is the only place that will learn an ID's severity,
  163.  * it should insert an ID into the appropriate list, but only if the ID
  164.  * doesn't exist in it or any other list yet. Because searching all three
  165.  * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
  166.  */
  167. enum {
  168.    FOUND_BIT = 1 << 0,
  169.    ENABLED_BIT = 1 << 1,
  170.    KNOWN_SEVERITY = 1 << 2,
  171.  
  172.    /* HashTable reserves zero as a return value meaning 'not found' */
  173.    NOT_FOUND = 0,
  174.    DISABLED = FOUND_BIT,
  175.    ENABLED = ENABLED_BIT | FOUND_BIT
  176. };
  177.  
  178. /**
  179.  * Returns the state of the given message source/type/ID tuple.
  180.  */
  181. static GLboolean
  182. should_log(struct gl_context *ctx,
  183.            enum mesa_debug_source source,
  184.            enum mesa_debug_type type,
  185.            GLuint id,
  186.            enum mesa_debug_severity severity)
  187. {
  188.    struct gl_debug_namespace *nspace =
  189.          &ctx->Debug.Namespaces[source][type];
  190.    uintptr_t state;
  191.  
  192.    /* In addition to not being able to store zero as a value, HashTable also
  193.       can't use zero as a key. */
  194.    if (id)
  195.       state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
  196.    else
  197.       state = nspace->ZeroID;
  198.  
  199.    /* Only do this once for each ID. This makes sure the ID exists in,
  200.       at most, one list, and does not pointlessly appear multiple times. */
  201.    if (!(state & KNOWN_SEVERITY)) {
  202.       struct gl_debug_severity *entry;
  203.  
  204.       if (state == NOT_FOUND) {
  205.          if (ctx->Debug.Defaults[severity][source][type])
  206.             state = ENABLED;
  207.          else
  208.             state = DISABLED;
  209.       }
  210.  
  211.       entry = malloc(sizeof *entry);
  212.       if (!entry)
  213.          goto out;
  214.  
  215.       state |= KNOWN_SEVERITY;
  216.  
  217.       if (id)
  218.          _mesa_HashInsert(nspace->IDs, id, (void*)state);
  219.       else
  220.          nspace->ZeroID = state;
  221.  
  222.       entry->ID = id;
  223.       insert_at_tail(&nspace->Severity[severity], &entry->link);
  224.    }
  225.  
  226. out:
  227.    return !!(state & ENABLED_BIT);
  228. }
  229.  
  230. /**
  231.  * Sets the state of the given message source/type/ID tuple.
  232.  */
  233. static void
  234. set_message_state(struct gl_context *ctx,
  235.                   enum mesa_debug_source source,
  236.                   enum mesa_debug_type type,
  237.                   GLuint id, GLboolean enabled)
  238. {
  239.    struct gl_debug_namespace *nspace =
  240.          &ctx->Debug.Namespaces[source][type];
  241.    uintptr_t state;
  242.  
  243.    /* In addition to not being able to store zero as a value, HashTable also
  244.       can't use zero as a key. */
  245.    if (id)
  246.       state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
  247.    else
  248.       state = nspace->ZeroID;
  249.  
  250.    if (state == NOT_FOUND)
  251.       state = enabled ? ENABLED : DISABLED;
  252.    else {
  253.       if (enabled)
  254.          state |= ENABLED_BIT;
  255.       else
  256.          state &= ~ENABLED_BIT;
  257.    }
  258.  
  259.    if (id)
  260.       _mesa_HashInsert(nspace->IDs, id, (void*)state);
  261.    else
  262.       nspace->ZeroID = state;
  263. }
  264.  
  265. /**
  266.  * 'buf' is not necessarily a null-terminated string. When logging, copy
  267.  * 'len' characters from it, store them in a new, null-terminated string,
  268.  * and remember the number of bytes used by that string, *including*
  269.  * the null terminator this time.
  270.  */
  271. static void
  272. _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
  273.               enum mesa_debug_type type, GLuint id,
  274.               enum mesa_debug_severity severity, GLint len, const char *buf)
  275. {
  276.    GLint nextEmpty;
  277.    struct gl_debug_msg *emptySlot;
  278.  
  279.    assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH);
  280.  
  281.    if (!should_log(ctx, source, type, id, severity))
  282.       return;
  283.  
  284.    if (ctx->Debug.Callback) {
  285.       ctx->Debug.Callback(debug_source_enums[source],
  286.                           debug_type_enums[type],
  287.                           id,
  288.                           debug_severity_enums[severity],
  289.                           len, buf, ctx->Debug.CallbackData);
  290.       return;
  291.    }
  292.  
  293.    if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
  294.       return;
  295.  
  296.    nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages)
  297.                           % MAX_DEBUG_LOGGED_MESSAGES;
  298.    emptySlot = &ctx->Debug.Log[nextEmpty];
  299.  
  300.    assert(!emptySlot->message && !emptySlot->length);
  301.  
  302.    emptySlot->message = malloc(len+1);
  303.    if (emptySlot->message) {
  304.       (void) strncpy(emptySlot->message, buf, (size_t)len);
  305.       emptySlot->message[len] = '\0';
  306.  
  307.       emptySlot->length = len+1;
  308.       emptySlot->source = source;
  309.       emptySlot->type = type;
  310.       emptySlot->id = id;
  311.       emptySlot->severity = severity;
  312.    } else {
  313.       static GLuint oom_msg_id = 0;
  314.       debug_get_id(&oom_msg_id);
  315.  
  316.       /* malloc failed! */
  317.       emptySlot->message = out_of_memory;
  318.       emptySlot->length = strlen(out_of_memory)+1;
  319.       emptySlot->source = MESA_DEBUG_SOURCE_OTHER;
  320.       emptySlot->type = MESA_DEBUG_TYPE_ERROR;
  321.       emptySlot->id = oom_msg_id;
  322.       emptySlot->severity = MESA_DEBUG_SEVERITY_HIGH;
  323.    }
  324.  
  325.    if (ctx->Debug.NumMessages == 0)
  326.       ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
  327.  
  328.    ctx->Debug.NumMessages++;
  329. }
  330.  
  331. /**
  332.  * Pop the oldest debug message out of the log.
  333.  * Writes the message string, including the null terminator, into 'buf',
  334.  * using up to 'bufSize' bytes. If 'bufSize' is too small, or
  335.  * if 'buf' is NULL, nothing is written.
  336.  *
  337.  * Returns the number of bytes written on success, or when 'buf' is NULL,
  338.  * the number that would have been written. A return value of 0
  339.  * indicates failure.
  340.  */
  341. static GLsizei
  342. _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
  343.               GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
  344. {
  345.    struct gl_debug_msg *msg;
  346.    GLsizei length;
  347.  
  348.    if (ctx->Debug.NumMessages == 0)
  349.       return 0;
  350.  
  351.    msg = &ctx->Debug.Log[ctx->Debug.NextMsg];
  352.    length = msg->length;
  353.  
  354.    assert(length > 0 && length == ctx->Debug.NextMsgLength);
  355.  
  356.    if (bufSize < length && buf != NULL)
  357.       return 0;
  358.  
  359.    if (severity)
  360.       *severity = debug_severity_enums[msg->severity];
  361.    if (source)
  362.       *source = debug_source_enums[msg->source];
  363.    if (type)
  364.       *type = debug_type_enums[msg->type];
  365.    if (id)
  366.       *id = msg->id;
  367.  
  368.    if (buf) {
  369.       assert(msg->message[length-1] == '\0');
  370.       (void) strncpy(buf, msg->message, (size_t)length);
  371.    }
  372.  
  373.    if (msg->message != (char*)out_of_memory)
  374.       free(msg->message);
  375.    msg->message = NULL;
  376.    msg->length = 0;
  377.  
  378.    ctx->Debug.NumMessages--;
  379.    ctx->Debug.NextMsg++;
  380.    ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
  381.    ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
  382.  
  383.    return length;
  384. }
  385.  
  386. /**
  387.  * Verify that source, type, and severity are valid enums.
  388.  * glDebugMessageInsertARB only accepts two values for 'source',
  389.  * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
  390.  * in any parameter, so handle those cases specially.
  391.  */
  392. static GLboolean
  393. validate_params(struct gl_context *ctx, unsigned caller,
  394.                 GLenum source, GLenum type, GLenum severity)
  395. {
  396. #define INSERT 1
  397. #define CONTROL 2
  398.    switch(source) {
  399.    case GL_DEBUG_SOURCE_APPLICATION_ARB:
  400.    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
  401.       break;
  402.    case GL_DEBUG_SOURCE_API_ARB:
  403.    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
  404.    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
  405.    case GL_DEBUG_SOURCE_OTHER_ARB:
  406.       if (caller != INSERT)
  407.          break;
  408.    case GL_DONT_CARE:
  409.       if (caller == CONTROL)
  410.          break;
  411.    default:
  412.       goto error;
  413.    }
  414.  
  415.    switch(type) {
  416.    case GL_DEBUG_TYPE_ERROR_ARB:
  417.    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
  418.    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
  419.    case GL_DEBUG_TYPE_PERFORMANCE_ARB:
  420.    case GL_DEBUG_TYPE_PORTABILITY_ARB:
  421.    case GL_DEBUG_TYPE_OTHER_ARB:
  422.       break;
  423.    case GL_DONT_CARE:
  424.       if (caller == CONTROL)
  425.          break;
  426.    default:
  427.       goto error;
  428.    }
  429.  
  430.    switch(severity) {
  431.    case GL_DEBUG_SEVERITY_HIGH_ARB:
  432.    case GL_DEBUG_SEVERITY_MEDIUM_ARB:
  433.    case GL_DEBUG_SEVERITY_LOW_ARB:
  434.       break;
  435.    case GL_DONT_CARE:
  436.       if (caller == CONTROL)
  437.          break;
  438.    default:
  439.       goto error;
  440.    }
  441.    return GL_TRUE;
  442.  
  443. error:
  444.    {
  445.       const char *callerstr;
  446.       if (caller == INSERT)
  447.          callerstr = "glDebugMessageInsertARB";
  448.       else if (caller == CONTROL)
  449.          callerstr = "glDebugMessageControlARB";
  450.       else
  451.          return GL_FALSE;
  452.  
  453.       _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s"
  454.                   "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
  455.                   source, type, severity);
  456.    }
  457.    return GL_FALSE;
  458. }
  459.  
  460. void GLAPIENTRY
  461. _mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
  462.                             GLenum severity, GLint length,
  463.                             const GLcharARB* buf)
  464. {
  465.    GET_CURRENT_CONTEXT(ctx);
  466.  
  467.    if (!validate_params(ctx, INSERT, source, type, severity))
  468.       return; /* GL_INVALID_ENUM */
  469.  
  470.    if (length < 0)
  471.       length = strlen(buf);
  472.  
  473.    if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
  474.       _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB"
  475.                  "(length=%d, which is not less than "
  476.                  "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length,
  477.                  MAX_DEBUG_MESSAGE_LENGTH);
  478.       return;
  479.    }
  480.  
  481.    _mesa_log_msg(ctx,
  482.                  gl_enum_to_debug_source(source),
  483.                  gl_enum_to_debug_type(type), id,
  484.                  gl_enum_to_debug_severity(severity), length, buf);
  485. }
  486.  
  487. GLuint GLAPIENTRY
  488. _mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
  489.                             GLenum* types, GLenum* ids, GLenum* severities,
  490.                             GLsizei* lengths, GLcharARB* messageLog)
  491. {
  492.    GET_CURRENT_CONTEXT(ctx);
  493.    GLuint ret;
  494.  
  495.    if (!messageLog)
  496.       logSize = 0;
  497.  
  498.    if (logSize < 0) {
  499.       _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB"
  500.                  "(logSize=%d : logSize must not be negative)", logSize);
  501.       return 0;
  502.    }
  503.  
  504.    for (ret = 0; ret < count; ret++) {
  505.       GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
  506.                                       logSize, messageLog);
  507.       if (!written)
  508.          break;
  509.  
  510.       if (messageLog) {
  511.          messageLog += written;
  512.          logSize -= written;
  513.       }
  514.       if (lengths) {
  515.          *lengths = written;
  516.          lengths++;
  517.       }
  518.  
  519.       if (severities)
  520.          severities++;
  521.       if (sources)
  522.          sources++;
  523.       if (types)
  524.          types++;
  525.       if (ids)
  526.          ids++;
  527.    }
  528.  
  529.    return ret;
  530. }
  531.  
  532. /**
  533.  * Set the state of all message IDs found in the given intersection of
  534.  * 'source', 'type', and 'severity'.  The _COUNT enum can be used for
  535.  * GL_DONT_CARE (include all messages in the class).
  536.  *
  537.  * This requires both setting the state of all previously seen message
  538.  * IDs in the hash table, and setting the default state for all
  539.  * applicable combinations of source/type/severity, so that all the
  540.  * yet-unknown message IDs that may be used in the future will be
  541.  * impacted as if they were already known.
  542.  */
  543. static void
  544. control_messages(struct gl_context *ctx,
  545.                  enum mesa_debug_source source,
  546.                  enum mesa_debug_type type,
  547.                  enum mesa_debug_severity severity,
  548.                  GLboolean enabled)
  549. {
  550.    int s, t, sev, smax, tmax, sevmax;
  551.  
  552.    if (source == MESA_DEBUG_SOURCE_COUNT) {
  553.       source = 0;
  554.       smax = MESA_DEBUG_SOURCE_COUNT;
  555.    } else {
  556.       smax = source+1;
  557.    }
  558.  
  559.    if (type == MESA_DEBUG_TYPE_COUNT) {
  560.       type = 0;
  561.       tmax = MESA_DEBUG_TYPE_COUNT;
  562.    } else {
  563.       tmax = type+1;
  564.    }
  565.  
  566.    if (severity == MESA_DEBUG_SEVERITY_COUNT) {
  567.       severity = 0;
  568.       sevmax = MESA_DEBUG_SEVERITY_COUNT;
  569.    } else {
  570.       sevmax = severity+1;
  571.    }
  572.  
  573.    for (sev = severity; sev < sevmax; sev++)
  574.       for (s = source; s < smax; s++)
  575.          for (t = type; t < tmax; t++) {
  576.             struct simple_node *node;
  577.             struct gl_debug_severity *entry;
  578.  
  579.             /* change the default for IDs we've never seen before. */
  580.             ctx->Debug.Defaults[sev][s][t] = enabled;
  581.  
  582.             /* Now change the state of IDs we *have* seen... */
  583.             foreach(node, &ctx->Debug.Namespaces[s][t].Severity[sev]) {
  584.                entry = (struct gl_debug_severity *)node;
  585.                set_message_state(ctx, s, t, entry->ID, enabled);
  586.             }
  587.          }
  588. }
  589.  
  590. /**
  591.  * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
  592.  * require special handling, since the IDs in them are controlled by clients,
  593.  * not the OpenGL implementation.
  594.  *
  595.  * 'count' is the length of the array 'ids'. If 'count' is nonzero, all
  596.  * the given IDs in the namespace defined by 'esource' and 'etype'
  597.  * will be affected.
  598.  *
  599.  * If 'count' is zero, this sets the state of all IDs that match
  600.  * the combination of 'esource', 'etype', and 'eseverity'.
  601.  */
  602. static void
  603. control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
  604.                      GLenum eseverity, GLsizei count, const GLuint *ids,
  605.                      GLboolean enabled)
  606. {
  607.    GLsizei i;
  608.    enum mesa_debug_source source = gl_enum_to_debug_source(esource);
  609.    enum mesa_debug_type type = gl_enum_to_debug_type(etype);
  610.    enum mesa_debug_severity severity = gl_enum_to_debug_severity(eseverity);
  611.  
  612.    for (i = 0; i < count; i++)
  613.       set_message_state(ctx, source, type, ids[i], enabled);
  614.  
  615.    if (count)
  616.       return;
  617.  
  618.    control_messages(ctx, source, type, severity, enabled);
  619. }
  620.  
  621. void GLAPIENTRY
  622. _mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type,
  623.                              GLenum gl_severity,
  624.                              GLsizei count, const GLuint *ids,
  625.                              GLboolean enabled)
  626. {
  627.    GET_CURRENT_CONTEXT(ctx);
  628.  
  629.    if (count < 0) {
  630.       _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageControlARB"
  631.                  "(count=%d : count must not be negative)", count);
  632.       return;
  633.    }
  634.  
  635.    if (!validate_params(ctx, CONTROL, gl_source, gl_type, gl_severity))
  636.       return; /* GL_INVALID_ENUM */
  637.  
  638.    if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE
  639.                  || gl_source == GL_DONT_CARE)) {
  640.       _mesa_error(ctx, GL_INVALID_OPERATION, "glDebugMessageControlARB"
  641.                  "(When passing an array of ids, severity must be"
  642.          " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.");
  643.       return;
  644.    }
  645.  
  646.    control_app_messages(ctx, gl_source, gl_type, gl_severity,
  647.                         count, ids, enabled);
  648. }
  649.  
  650. void GLAPIENTRY
  651. _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const void *userParam)
  652. {
  653.    GET_CURRENT_CONTEXT(ctx);
  654.    ctx->Debug.Callback = callback;
  655.    ctx->Debug.CallbackData = userParam;
  656. }
  657.  
  658. void
  659. _mesa_init_errors(struct gl_context *ctx)
  660. {
  661.    int s, t, sev;
  662.  
  663.    ctx->Debug.Callback = NULL;
  664.    ctx->Debug.SyncOutput = GL_FALSE;
  665.    ctx->Debug.Log[0].length = 0;
  666.    ctx->Debug.NumMessages = 0;
  667.    ctx->Debug.NextMsg = 0;
  668.    ctx->Debug.NextMsgLength = 0;
  669.  
  670.    /* Enable all the messages with severity HIGH or MEDIUM by default. */
  671.    memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH], GL_TRUE,
  672.           sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH]);
  673.    memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE,
  674.           sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM]);
  675.    memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW], GL_FALSE,
  676.           sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW]);
  677.  
  678.    /* Initialize state for filtering known debug messages. */
  679.    for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
  680.       for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
  681.          ctx->Debug.Namespaces[s][t].IDs = _mesa_NewHashTable();
  682.          assert(ctx->Debug.Namespaces[s][t].IDs);
  683.  
  684.          for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++)
  685.             make_empty_list(&ctx->Debug.Namespaces[s][t].Severity[sev]);
  686.       }
  687. }
  688.  
  689. static void
  690. do_nothing(GLuint key, void *data, void *userData)
  691. {
  692. }
  693.  
  694. void
  695. _mesa_free_errors_data(struct gl_context *ctx)
  696. {
  697.    enum mesa_debug_type t;
  698.    enum mesa_debug_source s;
  699.    enum mesa_debug_severity sev;
  700.  
  701.    /* Tear down state for filtering debug messages. */
  702.    for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
  703.       for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
  704.          _mesa_HashDeleteAll(ctx->Debug.Namespaces[s][t].IDs, do_nothing, NULL);
  705.          _mesa_DeleteHashTable(ctx->Debug.Namespaces[s][t].IDs);
  706.          for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
  707.             struct simple_node *node, *tmp;
  708.             struct gl_debug_severity *entry;
  709.  
  710.             foreach_s(node, tmp, &ctx->Debug.Namespaces[s][t].Severity[sev]) {
  711.                entry = (struct gl_debug_severity *)node;
  712.                free(entry);
  713.             }
  714.          }
  715.       }
  716. }
  717.  
  718. /**********************************************************************/
  719. /** \name Diagnostics */
  720. /*@{*/
  721.  
  722. static void
  723. output_if_debug(const char *prefixString, const char *outputString,
  724.                 GLboolean newline)
  725. {
  726.    static int debug = -1;
  727.    static FILE *fout = NULL;
  728.  
  729.    /* Init the local 'debug' var once.
  730.     * Note: the _mesa_init_debug() function should have been called
  731.     * by now so MESA_DEBUG_FLAGS will be initialized.
  732.     */
  733.    if (debug == -1) {
  734.       /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
  735.        * etc to the named file.  Otherwise, output to stderr.
  736.        */
  737.       const char *logFile = _mesa_getenv("MESA_LOG_FILE");
  738.       if (logFile)
  739.          fout = fopen(logFile, "w");
  740.       if (!fout)
  741.          fout = stderr;
  742. #ifdef DEBUG
  743.       /* in debug builds, print messages unless MESA_DEBUG="silent" */
  744.       if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
  745.          debug = 0;
  746.       else
  747.          debug = 1;
  748. #else
  749.       /* in release builds, be silent unless MESA_DEBUG is set */
  750.       debug = _mesa_getenv("MESA_DEBUG") != NULL;
  751. #endif
  752.    }
  753.  
  754.    /* Now only print the string if we're required to do so. */
  755.    if (debug) {
  756.       fprintf(fout, "%s: %s", prefixString, outputString);
  757.       if (newline)
  758.          fprintf(fout, "\n");
  759.       fflush(fout);
  760.  
  761. #if defined(_WIN32) && !defined(_WIN32_WCE)
  762.       /* stderr from windows applications without console is not usually
  763.        * visible, so communicate with the debugger instead */
  764.       {
  765.          char buf[4096];
  766.          _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
  767.          OutputDebugStringA(buf);
  768.       }
  769. #endif
  770.    }
  771. }
  772.  
  773. /**
  774.  * When a new type of error is recorded, print a message describing
  775.  * previous errors which were accumulated.
  776.  */
  777. static void
  778. flush_delayed_errors( struct gl_context *ctx )
  779. {
  780.    char s[MAX_DEBUG_MESSAGE_LENGTH];
  781.  
  782.    if (ctx->ErrorDebugCount) {
  783.       _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
  784.                      ctx->ErrorDebugCount,
  785.                      _mesa_lookup_enum_by_nr(ctx->ErrorValue));
  786.  
  787.       output_if_debug("Mesa", s, GL_TRUE);
  788.  
  789.       ctx->ErrorDebugCount = 0;
  790.    }
  791. }
  792.  
  793.  
  794. /**
  795.  * Report a warning (a recoverable error condition) to stderr if
  796.  * either DEBUG is defined or the MESA_DEBUG env var is set.
  797.  *
  798.  * \param ctx GL context.
  799.  * \param fmtString printf()-like format string.
  800.  */
  801. void
  802. _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
  803. {
  804.    char str[MAX_DEBUG_MESSAGE_LENGTH];
  805.    va_list args;
  806.    va_start( args, fmtString );  
  807.    (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
  808.    va_end( args );
  809.    
  810.    if (ctx)
  811.       flush_delayed_errors( ctx );
  812.  
  813.    output_if_debug("Mesa warning", str, GL_TRUE);
  814. }
  815.  
  816.  
  817. /**
  818.  * Report an internal implementation problem.
  819.  * Prints the message to stderr via fprintf().
  820.  *
  821.  * \param ctx GL context.
  822.  * \param fmtString problem description string.
  823.  */
  824. void
  825. _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
  826. {
  827.    va_list args;
  828.    char str[MAX_DEBUG_MESSAGE_LENGTH];
  829.    static int numCalls = 0;
  830.  
  831.    (void) ctx;
  832.  
  833.    if (numCalls < 50) {
  834.       numCalls++;
  835.  
  836.       va_start( args, fmtString );  
  837.       _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
  838.       va_end( args );
  839.       fprintf(stderr, "Mesa %s implementation error: %s\n",
  840.               PACKAGE_VERSION, str);
  841.       fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
  842.    }
  843. }
  844.  
  845. static GLboolean
  846. should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
  847. {
  848.    static GLint debug = -1;
  849.  
  850.    /* Check debug environment variable only once:
  851.     */
  852.    if (debug == -1) {
  853.       const char *debugEnv = _mesa_getenv("MESA_DEBUG");
  854.  
  855. #ifdef DEBUG
  856.       if (debugEnv && strstr(debugEnv, "silent"))
  857.          debug = GL_FALSE;
  858.       else
  859.          debug = GL_TRUE;
  860. #else
  861.       if (debugEnv)
  862.          debug = GL_TRUE;
  863.       else
  864.          debug = GL_FALSE;
  865. #endif
  866.    }
  867.  
  868.    if (debug) {
  869.       if (ctx->ErrorValue != error ||
  870.           ctx->ErrorDebugFmtString != fmtString) {
  871.          flush_delayed_errors( ctx );
  872.          ctx->ErrorDebugFmtString = fmtString;
  873.          ctx->ErrorDebugCount = 0;
  874.          return GL_TRUE;
  875.       }
  876.       ctx->ErrorDebugCount++;
  877.    }
  878.    return GL_FALSE;
  879. }
  880.  
  881. void
  882. _mesa_gl_debug(struct gl_context *ctx,
  883.                GLuint *id,
  884.                enum mesa_debug_type type,
  885.                enum mesa_debug_severity severity,
  886.                const char *fmtString, ...)
  887. {
  888.    char s[MAX_DEBUG_MESSAGE_LENGTH];
  889.    int len;
  890.    va_list args;
  891.  
  892.    debug_get_id(id);
  893.  
  894.    va_start(args, fmtString);
  895.    len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
  896.    va_end(args);
  897.  
  898.    _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, type,
  899.                  *id, severity, len, s);
  900. }
  901.  
  902.  
  903. /**
  904.  * Record an OpenGL state error.  These usually occur when the user
  905.  * passes invalid parameters to a GL function.
  906.  *
  907.  * If debugging is enabled (either at compile-time via the DEBUG macro, or
  908.  * run-time via the MESA_DEBUG environment variable), report the error with
  909.  * _mesa_debug().
  910.  *
  911.  * \param ctx the GL context.
  912.  * \param error the error value.
  913.  * \param fmtString printf() style format string, followed by optional args
  914.  */
  915. void
  916. _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
  917. {
  918.    GLboolean do_output, do_log;
  919.    /* Ideally this would be set up by the caller, so that we had proper IDs
  920.     * per different message.
  921.     */
  922.    static GLuint error_msg_id = 0;
  923.  
  924.    debug_get_id(&error_msg_id);
  925.  
  926.    do_output = should_output(ctx, error, fmtString);
  927.    do_log = should_log(ctx,
  928.                        MESA_DEBUG_SOURCE_API,
  929.                        MESA_DEBUG_TYPE_ERROR,
  930.                        error_msg_id,
  931.                        MESA_DEBUG_SEVERITY_HIGH);
  932.  
  933.    if (do_output || do_log) {
  934.       char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
  935.       int len;
  936.       va_list args;
  937.  
  938.       va_start(args, fmtString);
  939.       len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
  940.       va_end(args);
  941.  
  942.       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
  943.          /* Too long error message. Whoever calls _mesa_error should use
  944.           * shorter strings. */
  945.          ASSERT(0);
  946.          return;
  947.       }
  948.  
  949.       len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
  950.                            _mesa_lookup_enum_by_nr(error), s);
  951.       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
  952.          /* Same as above. */
  953.          ASSERT(0);
  954.          return;
  955.       }
  956.  
  957.       /* Print the error to stderr if needed. */
  958.       if (do_output) {
  959.          output_if_debug("Mesa: User error", s2, GL_TRUE);
  960.       }
  961.  
  962.       /* Log the error via ARB_debug_output if needed.*/
  963.       if (do_log) {
  964.          _mesa_log_msg(ctx,
  965.                        MESA_DEBUG_SOURCE_API,
  966.                        MESA_DEBUG_TYPE_ERROR,
  967.                        error_msg_id,
  968.                        MESA_DEBUG_SEVERITY_HIGH, len, s2);
  969.       }
  970.    }
  971.  
  972.    /* Set the GL context error state for glGetError. */
  973.    _mesa_record_error(ctx, error);
  974. }
  975.  
  976.  
  977. /**
  978.  * Report debug information.  Print error message to stderr via fprintf().
  979.  * No-op if DEBUG mode not enabled.
  980.  *
  981.  * \param ctx GL context.
  982.  * \param fmtString printf()-style format string, followed by optional args.
  983.  */
  984. void
  985. _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
  986. {
  987. #ifdef DEBUG
  988.    char s[MAX_DEBUG_MESSAGE_LENGTH];
  989.    va_list args;
  990.    va_start(args, fmtString);
  991.    _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
  992.    va_end(args);
  993.    output_if_debug("Mesa", s, GL_FALSE);
  994. #endif /* DEBUG */
  995.    (void) ctx;
  996.    (void) fmtString;
  997. }
  998.  
  999.  
  1000. /**
  1001.  * Report debug information from the shader compiler via GL_ARB_debug_output.
  1002.  *
  1003.  * \param ctx GL context.
  1004.  * \param type The namespace to which this message belongs.
  1005.  * \param id The message ID within the given namespace.
  1006.  * \param msg The message to output. Need not be null-terminated.
  1007.  * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
  1008.  */
  1009. void
  1010. _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint *id,
  1011.                     const char *msg, int len )
  1012. {
  1013.    enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
  1014.    enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
  1015.  
  1016.    debug_get_id(id);
  1017.  
  1018.    if (len < 0)
  1019.       len = strlen(msg);
  1020.  
  1021.    /* Truncate the message if necessary. */
  1022.    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
  1023.       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
  1024.  
  1025.    _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
  1026. }
  1027.  
  1028. /*@}*/
  1029.