mesa: Allow setting GL_TEXTURE_MAX_LEVEL to 0 with GL_TEXTURE_RECTANGLE.
[mesa.git] / src / mesa / main / errors.c
index e1a9fe2f506c952b7f74f4a582e8de2a53514259..9151718eab6c45491950d2df54bc39f37372037d 100644 (file)
 #include "mtypes.h"
 #include "version.h"
 #include "hash_table.h"
-#include "glapi/glthread.h"
 
-#define MESSAGE_LOG 1
-#define MESSAGE_LOG_ARB 2
-
-_glthread_DECLARE_STATIC_MUTEX(DynamicIDMutex);
+static mtx_t DynamicIDMutex = _MTX_INITIALIZER_NP;
 static GLuint NextDynamicID = 1;
 
 struct gl_debug_severity
@@ -81,6 +77,7 @@ static const GLenum debug_severity_enums[] = {
    GL_DEBUG_SEVERITY_NOTIFICATION,
 };
 
+
 static enum mesa_debug_source
 gl_enum_to_debug_source(GLenum e)
 {
@@ -117,6 +114,7 @@ gl_enum_to_debug_severity(GLenum e)
    return i;
 }
 
+
 /**
  * Handles generating a GL_ARB_debug_output message ID generated by the GL or
  * GLSL compiler.
@@ -134,13 +132,14 @@ static void
 debug_get_id(GLuint *id)
 {
    if (!(*id)) {
-      _glthread_LOCK_MUTEX(DynamicIDMutex);
+      mtx_lock(&DynamicIDMutex);
       if (!(*id))
          *id = NextDynamicID++;
-      _glthread_UNLOCK_MUTEX(DynamicIDMutex);
+      mtx_unlock(&DynamicIDMutex);
    }
 }
 
+
 /*
  * We store a bitfield in the hash table, with five possible values total.
  *
@@ -182,6 +181,50 @@ enum {
    ENABLED = ENABLED_BIT | FOUND_BIT
 };
 
+
+/**
+ * Return debug state for the context.  The debug state will be allocated
+ * and initialized upon the first call.
+ */
+struct gl_debug_state *
+_mesa_get_debug_state(struct gl_context *ctx)
+{
+   if (!ctx->Debug) {
+      ctx->Debug = CALLOC_STRUCT(gl_debug_state);
+      if (!ctx->Debug) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "allocating debug state");
+      }
+      else {
+         struct gl_debug_state *debug = ctx->Debug;
+         int s, t, sev;
+
+         /* Enable all the messages with severity HIGH or MEDIUM by default. */
+         memset(debug->Defaults[0][MESA_DEBUG_SEVERITY_HIGH], GL_TRUE,
+                sizeof debug->Defaults[0][MESA_DEBUG_SEVERITY_HIGH]);
+         memset(debug->Defaults[0][MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE,
+                sizeof debug->Defaults[0][MESA_DEBUG_SEVERITY_MEDIUM]);
+         memset(debug->Defaults[0][MESA_DEBUG_SEVERITY_LOW], GL_FALSE,
+                sizeof debug->Defaults[0][MESA_DEBUG_SEVERITY_LOW]);
+
+         /* Initialize state for filtering known debug messages. */
+         for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) {
+            for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
+               debug->Namespaces[0][s][t].IDs = _mesa_NewHashTable();
+               assert(debug->Namespaces[0][s][t].IDs);
+
+               for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
+                  make_empty_list(&debug->Namespaces[0][s][t].Severity[sev]);
+               }
+            }
+         }
+      }
+   }
+
+   return ctx->Debug;
+}
+
+
+
 /**
  * Returns the state of the given message source/type/ID tuple.
  */
@@ -192,52 +235,64 @@ should_log(struct gl_context *ctx,
            GLuint id,
            enum mesa_debug_severity severity)
 {
-   GLint gstack = ctx->Debug.GroupStackDepth;
-   struct gl_debug_namespace *nspace =
-         &ctx->Debug.Namespaces[gstack][source][type];
-   uintptr_t state;
+   struct gl_debug_state *debug;
+   uintptr_t state = 0;
 
-   if (!ctx->Debug.DebugOutput)
+   if (!ctx->Debug) {
+      /* no debug state set so far */
       return GL_FALSE;
+   }
 
-   /* In addition to not being able to store zero as a value, HashTable also
-      can't use zero as a key. */
-   if (id)
-      state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
-   else
-      state = nspace->ZeroID;
-
-   /* Only do this once for each ID. This makes sure the ID exists in,
-      at most, one list, and does not pointlessly appear multiple times. */
-   if (!(state & KNOWN_SEVERITY)) {
-      struct gl_debug_severity *entry;
-
-      if (state == NOT_FOUND) {
-         if (ctx->Debug.Defaults[gstack][severity][source][type])
-            state = ENABLED;
-         else
-            state = DISABLED;
-      }
-
-      entry = malloc(sizeof *entry);
-      if (!entry)
-         goto out;
+   debug = _mesa_get_debug_state(ctx);
+   if (debug) {
+      const GLint gstack = debug->GroupStackDepth;
+      struct gl_debug_namespace *nspace =
+         &debug->Namespaces[gstack][source][type];
 
-      state |= KNOWN_SEVERITY;
+      if (!debug->DebugOutput)
+         return GL_FALSE;
 
+      /* In addition to not being able to store zero as a value, HashTable also
+       * can't use zero as a key.
+       */
       if (id)
-         _mesa_HashInsert(nspace->IDs, id, (void*)state);
+         state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
       else
-         nspace->ZeroID = state;
+         state = nspace->ZeroID;
 
-      entry->ID = id;
-      insert_at_tail(&nspace->Severity[severity], &entry->link);
-   }
+      /* Only do this once for each ID. This makes sure the ID exists in,
+       * at most, one list, and does not pointlessly appear multiple times.
+       */
+      if (!(state & KNOWN_SEVERITY)) {
+         struct gl_debug_severity *entry;
+
+         if (state == NOT_FOUND) {
+            if (debug->Defaults[gstack][severity][source][type])
+               state = ENABLED;
+            else
+               state = DISABLED;
+         }
+
+         entry = malloc(sizeof *entry);
+         if (!entry)
+            goto out;
+
+         state |= KNOWN_SEVERITY;
 
+         if (id)
+            _mesa_HashInsert(nspace->IDs, id, (void*)state);
+         else
+            nspace->ZeroID = state;
+
+         entry->ID = id;
+         insert_at_tail(&nspace->Severity[severity], &entry->link);
+      }
+   }
 out:
    return !!(state & ENABLED_BIT);
 }
 
+
 /**
  * Sets the state of the given message source/type/ID tuple.
  */
@@ -247,33 +302,39 @@ set_message_state(struct gl_context *ctx,
                   enum mesa_debug_type type,
                   GLuint id, GLboolean enabled)
 {
-   GLint gstack = ctx->Debug.GroupStackDepth;
-   struct gl_debug_namespace *nspace =
-         &ctx->Debug.Namespaces[gstack][source][type];
-   uintptr_t state;
-
-   /* In addition to not being able to store zero as a value, HashTable also
-      can't use zero as a key. */
-   if (id)
-      state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
-   else
-      state = nspace->ZeroID;
-
-   if (state == NOT_FOUND)
-      state = enabled ? ENABLED : DISABLED;
-   else {
-      if (enabled)
-         state |= ENABLED_BIT;
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
+
+   if (debug) {
+      GLint gstack = debug->GroupStackDepth;
+      struct gl_debug_namespace *nspace =
+         &debug->Namespaces[gstack][source][type];
+      uintptr_t state;
+
+      /* In addition to not being able to store zero as a value, HashTable also
+       * can't use zero as a key.
+       */
+      if (id)
+         state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
       else
-         state &= ~ENABLED_BIT;
-   }
+         state = nspace->ZeroID;
+
+      if (state == NOT_FOUND)
+         state = enabled ? ENABLED : DISABLED;
+      else {
+         if (enabled)
+            state |= ENABLED_BIT;
+         else
+            state &= ~ENABLED_BIT;
+      }
 
-   if (id)
-      _mesa_HashInsert(nspace->IDs, id, (void*)state);
-   else
-      nspace->ZeroID = state;
+      if (id)
+         _mesa_HashInsert(nspace->IDs, id, (void*)state);
+      else
+         nspace->ZeroID = state;
+   }
 }
 
+
 static void
 store_message_details(struct gl_debug_msg *emptySlot,
                       enum mesa_debug_source source,
@@ -307,37 +368,6 @@ store_message_details(struct gl_debug_msg *emptySlot,
    }
 }
 
- /**
- * Remap any type exclusive to KHR_debug to something suitable
- * for ARB_debug_output
- */
-inline static int
-remap_type(GLenum type) {
-
-   switch(type) {
-   case GL_DEBUG_TYPE_MARKER:
-   case GL_DEBUG_TYPE_PUSH_GROUP:
-   case GL_DEBUG_TYPE_POP_GROUP:
-      type = GL_DEBUG_TYPE_OTHER;
-   default:
-      ;
-   }
-
-  return type;
-}
-
-/**
- * Remap severity exclusive to KHR_debug to something suitable
- * for ARB_debug_output
- */
-inline static int
-remap_severity(GLenum severity) {
-
-   if (GL_DEBUG_SEVERITY_NOTIFICATION == severity)
-      severity = GL_DEBUG_SEVERITY_LOW;
-
-   return severity;
-}
 
 /**
  * 'buf' is not necessarily a null-terminated string. When logging, copy
@@ -346,49 +376,47 @@ remap_severity(GLenum severity) {
  * the null terminator this time.
  */
 static void
-_mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
-              enum mesa_debug_type type, GLuint id,
-              enum mesa_debug_severity severity, GLint len, const char *buf)
+log_msg(struct gl_context *ctx, enum mesa_debug_source source,
+        enum mesa_debug_type type, GLuint id,
+        enum mesa_debug_severity severity, GLint len, const char *buf)
 {
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
    GLint nextEmpty;
    struct gl_debug_msg *emptySlot;
 
+   if (!debug)
+      return;
+
    assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH);
 
    if (!should_log(ctx, source, type, id, severity))
       return;
 
-   if (ctx->Debug.Callback) {
+   if (debug->Callback) {
        GLenum gl_type = debug_type_enums[type];
        GLenum gl_severity = debug_severity_enums[severity];
 
-       if (ctx->Debug.ARBCallback) {
-          gl_severity = remap_severity(gl_severity);
-          gl_type = remap_type(gl_type);
-      }
-      ctx->Debug.Callback(debug_source_enums[source],
-                          gl_type,
-                          id,
-                          gl_severity,
-                          len, buf, ctx->Debug.CallbackData);
+      debug->Callback(debug_source_enums[source], gl_type, id, gl_severity,
+                      len, buf, debug->CallbackData);
       return;
    }
 
-   if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
+   if (debug->NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
       return;
 
-   nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages)
+   nextEmpty = (debug->NextMsg + debug->NumMessages)
                           % MAX_DEBUG_LOGGED_MESSAGES;
-   emptySlot = &ctx->Debug.Log[nextEmpty];
+   emptySlot = &debug->Log[nextEmpty];
 
    store_message_details(emptySlot, source, type, id, severity, len, buf);
 
-   if (ctx->Debug.NumMessages == 0)
-      ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
+   if (debug->NumMessages == 0)
+      debug->NextMsgLength = debug->Log[debug->NextMsg].length;
 
-   ctx->Debug.NumMessages++;
+   debug->NumMessages++;
 }
 
+
 /**
  * Pop the oldest debug message out of the log.
  * Writes the message string, including the null terminator, into 'buf',
@@ -400,38 +428,39 @@ _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
  * indicates failure.
  */
 static GLsizei
-_mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
-              GLuint *id, GLenum *severity, GLsizei bufSize, char *buf,
-              unsigned caller)
+get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
+        GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
 {
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
    struct gl_debug_msg *msg;
    GLsizei length;
 
-   if (ctx->Debug.NumMessages == 0)
+   if (!debug || debug->NumMessages == 0)
       return 0;
 
-   msg = &ctx->Debug.Log[ctx->Debug.NextMsg];
+   msg = &debug->Log[debug->NextMsg];
    length = msg->length;
 
-   assert(length > 0 && length == ctx->Debug.NextMsgLength);
+   assert(length > 0 && length == debug->NextMsgLength);
 
    if (bufSize < length && buf != NULL)
       return 0;
 
    if (severity) {
       *severity = debug_severity_enums[msg->severity];
-      if (caller == MESSAGE_LOG_ARB)
-         *severity = remap_severity(*severity);
    }
-   if (source)
+
+   if (source) {
       *source = debug_source_enums[msg->source];
+   }
+
    if (type) {
       *type = debug_type_enums[msg->type];
-      if (caller == MESSAGE_LOG_ARB)
-         *type = remap_type(*type);
    }
-   if (id)
+
+   if (id) {
       *id = msg->id;
+   }
 
    if (buf) {
       assert(msg->message[length-1] == '\0');
@@ -443,22 +472,20 @@ _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
    msg->message = NULL;
    msg->length = 0;
 
-   ctx->Debug.NumMessages--;
-   ctx->Debug.NextMsg++;
-   ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
-   ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
+   debug->NumMessages--;
+   debug->NextMsg++;
+   debug->NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
+   debug->NextMsgLength = debug->Log[debug->NextMsg].length;
 
    return length;
 }
 
+
 /**
  * Verify that source, type, and severity are valid enums.
- * glDebugMessageInsertARB only accepts two values for 'source',
- * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
- * in any parameter, so handle those cases specially.
  *
- * There is also special cases for handling values available in
- * GL_KHR_debug that are not avaliable in GL_ARB_debug_output
+ * The 'caller' param is used for handling values available
+ * only in glDebugMessageInsert or glDebugMessageControl
  */
 static GLboolean
 validate_params(struct gl_context *ctx, unsigned caller,
@@ -467,8 +494,6 @@ validate_params(struct gl_context *ctx, unsigned caller,
 {
 #define INSERT 1
 #define CONTROL 2
-#define INSERT_ARB 3
-#define CONTROL_ARB 4
    switch(source) {
    case GL_DEBUG_SOURCE_APPLICATION_ARB:
    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
@@ -477,11 +502,15 @@ validate_params(struct gl_context *ctx, unsigned caller,
    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
    case GL_DEBUG_SOURCE_OTHER_ARB:
-      if (caller != INSERT || caller == INSERT_ARB)
+      if (caller != INSERT)
          break;
+      else
+         goto error;
    case GL_DONT_CARE:
-      if (caller == CONTROL || caller == CONTROL_ARB)
+      if (caller == CONTROL)
          break;
+      else
+         goto error;
    default:
       goto error;
    }
@@ -493,14 +522,15 @@ validate_params(struct gl_context *ctx, unsigned caller,
    case GL_DEBUG_TYPE_PERFORMANCE_ARB:
    case GL_DEBUG_TYPE_PORTABILITY_ARB:
    case GL_DEBUG_TYPE_OTHER_ARB:
-      break;
    case GL_DEBUG_TYPE_MARKER:
-      /* this value is only valid for GL_KHR_debug functions */
-      if (caller == CONTROL || caller == INSERT)
-         break;
+      break;
+   case GL_DEBUG_TYPE_PUSH_GROUP:
+   case GL_DEBUG_TYPE_POP_GROUP:
    case GL_DONT_CARE:
-      if (caller == CONTROL || caller == CONTROL_ARB)
+      if (caller == CONTROL)
          break;
+      else
+         goto error;
    default:
       goto error;
    }
@@ -509,28 +539,27 @@ validate_params(struct gl_context *ctx, unsigned caller,
    case GL_DEBUG_SEVERITY_HIGH_ARB:
    case GL_DEBUG_SEVERITY_MEDIUM_ARB:
    case GL_DEBUG_SEVERITY_LOW_ARB:
-      break;
    case GL_DEBUG_SEVERITY_NOTIFICATION:
-      /* this value is only valid for GL_KHR_debug functions */
-      if (caller == CONTROL || caller == INSERT)
-         break;
+      break;
    case GL_DONT_CARE:
-      if (caller == CONTROL || caller == CONTROL_ARB)
+      if (caller == CONTROL)
          break;
+      else
+         goto error;
    default:
       goto error;
    }
    return GL_TRUE;
 
 error:
-   {
-      _mesa_error(ctx, GL_INVALID_ENUM, "bad values passed to %s"
-                  "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
-                  source, type, severity);
-   }
+   _mesa_error(ctx, GL_INVALID_ENUM, "bad values passed to %s"
+               "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
+               source, type, severity);
+
    return GL_FALSE;
 }
 
+
 /**
  * Set the state of all message IDs found in the given intersection of
  * 'source', 'type', and 'severity'.  The _COUNT enum can be used for
@@ -549,8 +578,12 @@ control_messages(struct gl_context *ctx,
                  enum mesa_debug_severity severity,
                  GLboolean enabled)
 {
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
    int s, t, sev, smax, tmax, sevmax;
-   GLint gstack = ctx->Debug.GroupStackDepth;
+   const GLint gstack = debug ? debug->GroupStackDepth : 0;
+
+   if (!debug)
+      return;
 
    if (source == MESA_DEBUG_SOURCE_COUNT) {
       source = 0;
@@ -573,23 +606,26 @@ control_messages(struct gl_context *ctx,
       sevmax = severity+1;
    }
 
-   for (sev = severity; sev < sevmax; sev++)
-      for (s = source; s < smax; s++)
+   for (sev = severity; sev < sevmax; sev++) {
+      for (s = source; s < smax; s++) {
          for (t = type; t < tmax; t++) {
             struct simple_node *node;
             struct gl_debug_severity *entry;
 
             /* change the default for IDs we've never seen before. */
-            ctx->Debug.Defaults[gstack][sev][s][t] = enabled;
+            debug->Defaults[gstack][sev][s][t] = enabled;
 
             /* Now change the state of IDs we *have* seen... */
-            foreach(node, &ctx->Debug.Namespaces[gstack][s][t].Severity[sev]) {
+            foreach(node, &debug->Namespaces[gstack][s][t].Severity[sev]) {
                entry = (struct gl_debug_severity *)node;
                set_message_state(ctx, s, t, entry->ID, enabled);
             }
          }
+      }
+   }
 }
 
+
 /**
  * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
  * require special handling, since the IDs in them are controlled by clients,
@@ -621,42 +657,6 @@ control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
    control_messages(ctx, source, type, severity, enabled);
 }
 
-/**
- * This is a generic message control function for use by both
- * glDebugMessageControlARB and glDebugMessageControl.
- */
-static void
-message_control(GLenum gl_source, GLenum gl_type,
-                GLenum gl_severity,
-                GLsizei count, const GLuint *ids,
-                GLboolean enabled,
-                unsigned caller, const char *callerstr)
-{
-   GET_CURRENT_CONTEXT(ctx);
-
-   if (count < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "%s(count=%d : count must not be negative)", callerstr,
-                  count);
-      return;
-   }
-
-   if (!validate_params(ctx, caller, callerstr, gl_source, gl_type,
-                        gl_severity))
-      return; /* GL_INVALID_ENUM */
-
-   if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE
-                 || gl_source == GL_DONT_CARE)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(When passing an array of ids, severity must be"
-         " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.",
-                  callerstr);
-      return;
-   }
-
-   control_app_messages(ctx, gl_source, gl_type, gl_severity,
-                        count, ids, enabled);
-}
 
 /**
  * This is a generic message insert function.
@@ -665,7 +665,7 @@ message_control(GLenum gl_source, GLenum gl_type,
  */
 static void
 message_insert(GLenum source, GLenum type, GLuint id,
-               GLenum severity, GLint length, const GLcharbuf,
+               GLenum severity, GLint length, const GLchar *buf,
                const char *callerstr)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -681,21 +681,74 @@ message_insert(GLenum source, GLenum type, GLuint id,
       return;
    }
 
-   _mesa_log_msg(ctx,
-                 gl_enum_to_debug_source(source),
-                 gl_enum_to_debug_type(type), id,
-                 gl_enum_to_debug_severity(severity), length, buf);
+   log_msg(ctx,
+           gl_enum_to_debug_source(source),
+           gl_enum_to_debug_type(type), id,
+           gl_enum_to_debug_severity(severity), length, buf);
+}
+
+
+static void
+do_nothing(GLuint key, void *data, void *userData)
+{
 }
 
+
 /**
- * This is a generic message insert function for use by both
- * glGetDebugMessageLogARB and glGetDebugMessageLog.
+ * Free context state pertaining to error/debug state for the given stack
+ * depth.
  */
-static GLuint
-get_message_log(GLuint count, GLsizei logSize, GLenum* sources,
-                GLenum* types, GLenum* ids, GLenum* severities,
-                GLsizei* lengths, GLchar* messageLog,
-                unsigned caller, const char *callerstr)
+static void
+free_errors_data(struct gl_context *ctx, GLint gstack)
+{
+   struct gl_debug_state *debug = ctx->Debug;
+   enum mesa_debug_type t;
+   enum mesa_debug_source s;
+   enum mesa_debug_severity sev;
+
+   assert(debug);
+
+   /* Tear down state for filtering debug messages. */
+   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) {
+      for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
+         _mesa_HashDeleteAll(debug->Namespaces[gstack][s][t].IDs,
+                             do_nothing, NULL);
+         _mesa_DeleteHashTable(debug->Namespaces[gstack][s][t].IDs);
+         for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
+            struct simple_node *node, *tmp;
+            struct gl_debug_severity *entry;
+
+            foreach_s(node, tmp,
+                      &debug->Namespaces[gstack][s][t].Severity[sev]) {
+               entry = (struct gl_debug_severity *)node;
+               free(entry);
+            }
+         }
+      }
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_DebugMessageInsert(GLenum source, GLenum type, GLuint id,
+                         GLenum severity, GLint length,
+                         const GLchar *buf)
+{
+   const char *callerstr = "glDebugMessageInsert";
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!validate_params(ctx, INSERT, callerstr, source, type, severity))
+      return; /* GL_INVALID_ENUM */
+
+   message_insert(source, type, id, severity, length, buf, callerstr);
+}
+
+
+GLuint GLAPIENTRY
+_mesa_GetDebugMessageLog(GLuint count, GLsizei logSize, GLenum *sources,
+                         GLenum *types, GLenum *ids, GLenum *severities,
+                         GLsizei *lengths, GLchar *messageLog)
 {
    GET_CURRENT_CONTEXT(ctx);
    GLuint ret;
@@ -705,14 +758,14 @@ get_message_log(GLuint count, GLsizei logSize, GLenum* sources,
 
    if (logSize < 0) {
       _mesa_error(ctx, GL_INVALID_VALUE,
-                  "%s(logSize=%d : logSize must not be negative)", callerstr,
-                  logSize);
+                  "glGetDebugMessageLog(logSize=%d : logSize must not be"
+                  " negative)", logSize);
       return 0;
    }
 
    for (ret = 0; ret < count; ret++) {
-      GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
-                                      logSize, messageLog, caller);
+      GLsizei written = get_msg(ctx, sources, types, ids, severities,
+                                logSize, messageLog);
       if (!written)
          break;
 
@@ -738,97 +791,69 @@ get_message_log(GLuint count, GLsizei logSize, GLenum* sources,
    return ret;
 }
 
-static void
-do_nothing(GLuint key, void *data, void *userData)
-{
-}
-
-static void
-free_errors_data(struct gl_context *ctx, GLint gstack)
-{
-   enum mesa_debug_type t;
-   enum mesa_debug_source s;
-   enum mesa_debug_severity sev;
-
-   /* Tear down state for filtering debug messages. */
-   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
-      for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
-         _mesa_HashDeleteAll(ctx->Debug.Namespaces[gstack][s][t].IDs,
-                             do_nothing, NULL);
-         _mesa_DeleteHashTable(ctx->Debug.Namespaces[gstack][s][t].IDs);
-         for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
-            struct simple_node *node, *tmp;
-            struct gl_debug_severity *entry;
-
-            foreach_s(node, tmp,
-                      &ctx->Debug.Namespaces[gstack][s][t].Severity[sev]) {
-               entry = (struct gl_debug_severity *)node;
-               free(entry);
-            }
-         }
-      }
-}
 
 void GLAPIENTRY
-_mesa_DebugMessageInsert(GLenum source, GLenum type, GLuint id,
-                         GLenum severity, GLint length,
-                         const GLchar* buf)
+_mesa_DebugMessageControl(GLenum gl_source, GLenum gl_type,
+                          GLenum gl_severity, GLsizei count,
+                          const GLuint *ids, GLboolean enabled)
 {
-   const char *callerstr = "glDebugMessageInsert";
+   const char *callerstr = "glDebugMessageControl";
 
    GET_CURRENT_CONTEXT(ctx);
 
-   if (!validate_params(ctx, INSERT, callerstr, source, type, severity))
+   if (count < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s(count=%d : count must not be negative)", callerstr,
+                  count);
+      return;
+   }
+
+   if (!validate_params(ctx, CONTROL, callerstr, gl_source, gl_type,
+                        gl_severity))
       return; /* GL_INVALID_ENUM */
 
-   message_insert(source, type, id, severity, length, buf,
+   if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE
+                 || gl_source == GL_DONT_CARE)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(When passing an array of ids, severity must be"
+         " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.",
                   callerstr);
-}
-
-GLuint GLAPIENTRY
-_mesa_GetDebugMessageLog(GLuint count, GLsizei logSize, GLenum* sources,
-                         GLenum* types, GLenum* ids, GLenum* severities,
-                         GLsizei* lengths, GLchar* messageLog)
-{
-   const char *callerstr = "glGetDebugMessageLog";
+      return;
+   }
 
-   return get_message_log(count, logSize, sources, types, ids, severities,
-                          lengths, messageLog, MESSAGE_LOG, callerstr);
+   control_app_messages(ctx, gl_source, gl_type, gl_severity,
+                        count, ids, enabled);
 }
 
-void GLAPIENTRY
-_mesa_DebugMessageControl(GLenum source, GLenum type, GLenum severity,
-                          GLsizei count, const GLuint *ids,
-                          GLboolean enabled)
-{
-   const char *callerstr = "glDebugMessageControl";
-
-   message_control(source, type, severity, count, ids,
-                   enabled, CONTROL, callerstr);
-}
 
 void GLAPIENTRY
 _mesa_DebugMessageCallback(GLDEBUGPROC callback, const void *userParam)
 {
    GET_CURRENT_CONTEXT(ctx);
-   ctx->Debug.Callback = callback;
-   ctx->Debug.CallbackData = userParam;
-   ctx->Debug.ARBCallback = GL_FALSE;
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
+   if (debug) {
+      debug->Callback = callback;
+      debug->CallbackData = userParam;
+   }
 }
 
+
 void GLAPIENTRY
 _mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
                      const GLchar *message)
 {
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
    const char *callerstr = "glPushDebugGroup";
    int s, t, sev;
    GLint prevStackDepth;
    GLint currStackDepth;
    struct gl_debug_msg *emptySlot;
 
-   GET_CURRENT_CONTEXT(ctx);
+   if (!debug)
+      return;
 
-   if (ctx->Debug.GroupStackDepth >= MAX_DEBUG_GROUP_STACK_DEPTH-1) {
+   if (debug->GroupStackDepth >= MAX_DEBUG_GROUP_STACK_DEPTH-1) {
       _mesa_error(ctx, GL_STACK_OVERFLOW, "%s", callerstr);
       return;
    }
@@ -847,16 +872,16 @@ _mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
                   GL_DEBUG_SEVERITY_NOTIFICATION, length,
                   message, callerstr);
 
-   prevStackDepth = ctx->Debug.GroupStackDepth;
-   ctx->Debug.GroupStackDepth++;
-   currStackDepth = ctx->Debug.GroupStackDepth;
+   prevStackDepth = debug->GroupStackDepth;
+   debug->GroupStackDepth++;
+   currStackDepth = debug->GroupStackDepth;
 
    /* pop reuses the message details from push so we store this */
    if (length < 0)
       length = strlen(message);
-   emptySlot = &ctx->Debug.DebugGroupMsgs[ctx->Debug.GroupStackDepth];
+   emptySlot = &debug->DebugGroupMsgs[debug->GroupStackDepth];
    store_message_details(emptySlot, gl_enum_to_debug_source(source),
-                         gl_enum_to_debug_source(GL_DEBUG_TYPE_PUSH_GROUP),
+                         gl_enum_to_debug_type(GL_DEBUG_TYPE_PUSH_GROUP),
                          id,
                    gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
                          length, message);
@@ -864,60 +889,66 @@ _mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
    /* inherit the control volume of the debug group previously residing on
     * the top of the debug group stack
     */
-   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
+   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) {
       for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
          /* copy id settings */
-         ctx->Debug.Namespaces[currStackDepth][s][t].IDs =
-            _mesa_HashClone(ctx->Debug.Namespaces[prevStackDepth][s][t].IDs);
+         debug->Namespaces[currStackDepth][s][t].IDs =
+            _mesa_HashClone(debug->Namespaces[prevStackDepth][s][t].IDs);
 
          for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
             struct gl_debug_severity *entry, *prevEntry;
             struct simple_node *node;
 
             /* copy default settings for unknown ids */
-            ctx->Debug.Defaults[currStackDepth][sev][s][t] = ctx->Debug.Defaults[prevStackDepth][sev][s][t];
+            debug->Defaults[currStackDepth][sev][s][t] =
+               debug->Defaults[prevStackDepth][sev][s][t];
 
             /* copy known id severity settings */
-            make_empty_list(&ctx->Debug.Namespaces[currStackDepth][s][t].Severity[sev]);
-            foreach(node, &ctx->Debug.Namespaces[prevStackDepth][s][t].Severity[sev]) {
+            make_empty_list(&debug->Namespaces[currStackDepth][s][t].Severity[sev]);
+            foreach(node, &debug->Namespaces[prevStackDepth][s][t].Severity[sev]) {
                prevEntry = (struct gl_debug_severity *)node;
                entry = malloc(sizeof *entry);
                if (!entry)
                   return;
 
                entry->ID = prevEntry->ID;
-               insert_at_tail(&ctx->Debug.Namespaces[currStackDepth][s][t].Severity[sev], &entry->link);
+               insert_at_tail(&debug->Namespaces[currStackDepth][s][t].Severity[sev], &entry->link);
             }
          }
       }
+   }
 }
 
+
 void GLAPIENTRY
-_mesa_PopDebugGroup()
+_mesa_PopDebugGroup(void)
 {
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_debug_state *debug = _mesa_get_debug_state(ctx);
    const char *callerstr = "glPopDebugGroup";
    struct gl_debug_msg *gdmessage;
    GLint prevStackDepth;
 
-   GET_CURRENT_CONTEXT(ctx);
+   if (!debug)
+      return;
 
-   if (ctx->Debug.GroupStackDepth <= 0) {
+   if (debug->GroupStackDepth <= 0) {
       _mesa_error(ctx, GL_STACK_UNDERFLOW, "%s", callerstr);
       return;
    }
 
-   prevStackDepth = ctx->Debug.GroupStackDepth;
-   ctx->Debug.GroupStackDepth--;
+   prevStackDepth = debug->GroupStackDepth;
+   debug->GroupStackDepth--;
 
-   gdmessage = &ctx->Debug.DebugGroupMsgs[prevStackDepth];
-   /* using _mesa_log_msg() directly here as verification of parameters
+   gdmessage = &debug->DebugGroupMsgs[prevStackDepth];
+   /* using log_msg() directly here as verification of parameters
     * already done in push
     */
-   _mesa_log_msg(ctx, gdmessage->source,
-                 gl_enum_to_debug_type(GL_DEBUG_TYPE_POP_GROUP),
-                 gdmessage->id,
-                 gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
-                 gdmessage->length, gdmessage->message);
+   log_msg(ctx, gdmessage->source,
+           gl_enum_to_debug_type(GL_DEBUG_TYPE_POP_GROUP),
+           gdmessage->id,
+           gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
+           gdmessage->length, gdmessage->message);
 
    if (gdmessage->message != (char*)out_of_memory)
       free(gdmessage->message);
@@ -928,100 +959,34 @@ _mesa_PopDebugGroup()
    free_errors_data(ctx, prevStackDepth);
 }
 
-void GLAPIENTRY
-_mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
-                            GLenum severity, GLint length,
-                            const GLcharARB* buf)
-{
-   const char *callerstr = "glDebugMessageInsertARB";
-
-   GET_CURRENT_CONTEXT(ctx);
-
-   if (!validate_params(ctx, INSERT_ARB, callerstr, source, type, severity))
-      return; /* GL_INVALID_ENUM */
-
-   message_insert(source, type, id, severity, length, buf,
-                  callerstr);
-}
-
-GLuint GLAPIENTRY
-_mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
-                            GLenum* types, GLenum* ids, GLenum* severities,
-                            GLsizei* lengths, GLcharARB* messageLog)
-{
-   const char *callerstr = "glGetDebugMessageLogARB";
-
-   return get_message_log(count, logSize, sources, types, ids, severities,
-                          lengths, messageLog, MESSAGE_LOG_ARB, callerstr);
-}
-
-void GLAPIENTRY
-_mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type,
-                             GLenum gl_severity,
-                             GLsizei count, const GLuint *ids,
-                             GLboolean enabled)
-{
-   const char *callerstr = "glDebugMessageControlARB";
-
-   message_control(gl_source, gl_type, gl_severity, count, ids,
-                   enabled, CONTROL_ARB, callerstr);
-}
-
-void GLAPIENTRY
-_mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const void *userParam)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   ctx->Debug.Callback = callback;
-   ctx->Debug.CallbackData = userParam;
-   ctx->Debug.ARBCallback = GL_TRUE;
-}
 
 void
 _mesa_init_errors(struct gl_context *ctx)
 {
-   int s, t, sev;
-
-   ctx->Debug.Callback = NULL;
-   ctx->Debug.SyncOutput = GL_FALSE;
-   ctx->Debug.Log[0].length = 0;
-   ctx->Debug.NumMessages = 0;
-   ctx->Debug.NextMsg = 0;
-   ctx->Debug.NextMsgLength = 0;
-   ctx->Debug.GroupStackDepth = 0;
-
-   /* Enable all the messages with severity HIGH or MEDIUM by default. */
-   memset(ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_HIGH], GL_TRUE,
-          sizeof ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_HIGH]);
-   memset(ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE,
-          sizeof ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_MEDIUM]);
-   memset(ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_LOW], GL_FALSE,
-          sizeof ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_LOW]);
-
-   /* Initialize state for filtering known debug messages. */
-   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
-      for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
-         ctx->Debug.Namespaces[0][s][t].IDs = _mesa_NewHashTable();
-         assert(ctx->Debug.Namespaces[0][s][t].IDs);
-
-         for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++)
-            make_empty_list(&ctx->Debug.Namespaces[0][s][t].Severity[sev]);
-      }
+   /* no-op */
 }
 
+
 /**
  * Loop through debug group stack tearing down states for
- * filtering debug messages.
+ * filtering debug messages.  Then free debug output state.
  */
 void
 _mesa_free_errors_data(struct gl_context *ctx)
 {
-   GLint i;
+   if (ctx->Debug) {
+      GLint i;
 
-   for (i = 0; i <= ctx->Debug.GroupStackDepth; i++) {
-      free_errors_data(ctx, i);
+      for (i = 0; i <= ctx->Debug->GroupStackDepth; i++) {
+         free_errors_data(ctx, i);
+      }
+      FREE(ctx->Debug);
+      /* set to NULL just in case it is used before context is completely gone. */
+      ctx->Debug = NULL;
    }
 }
 
+
 /**********************************************************************/
 /** \name Diagnostics */
 /*@{*/
@@ -1077,6 +1042,7 @@ output_if_debug(const char *prefixString, const char *outputString,
    }
 }
 
+
 /**
  * When a new type of error is recorded, print a message describing
  * previous errors which were accumulated.
@@ -1149,6 +1115,7 @@ _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
    }
 }
 
+
 static GLboolean
 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
 {
@@ -1185,6 +1152,7 @@ should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
    return GL_FALSE;
 }
 
+
 void
 _mesa_gl_debug(struct gl_context *ctx,
                GLuint *id,
@@ -1202,8 +1170,7 @@ _mesa_gl_debug(struct gl_context *ctx,
    len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
    va_end(args);
 
-   _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, type,
-                 *id, severity, len, s);
+   log_msg(ctx, MESA_DEBUG_SOURCE_API, type, *id, severity, len, s);
 }
 
 
@@ -1248,7 +1215,8 @@ _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
 
       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
          /* Too long error message. Whoever calls _mesa_error should use
-          * shorter strings. */
+          * shorter strings.
+          */
          ASSERT(0);
          return;
       }
@@ -1268,11 +1236,8 @@ _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
 
       /* Log the error via ARB_debug_output if needed.*/
       if (do_log) {
-         _mesa_log_msg(ctx,
-                       MESA_DEBUG_SOURCE_API,
-                       MESA_DEBUG_TYPE_ERROR,
-                       error_msg_id,
-                       MESA_DEBUG_SEVERITY_HIGH, len, s2);
+         log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR,
+                 error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2);
       }
    }
 
@@ -1329,7 +1294,7 @@ _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint *id,
    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
 
-   _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
+   log_msg(ctx, source, type, *id, severity, len, msg);
 }
 
 /*@}*/