mesa: Implement glPushDebugGroup and glPopDebugGroup
authorTimothy Arceri <t_arceri@yahoo.com.au>
Mon, 26 Aug 2013 07:01:16 +0000 (17:01 +1000)
committerBrian Paul <brianp@vmware.com>
Wed, 4 Sep 2013 13:47:48 +0000 (07:47 -0600)
V4: fixes _mesa_error() compiler warnings (BrianP).

V3: removed C++ style comment

V2: fixed spelling typo in comment

Signed-off-by: Timothy Arceri <t_arceri@yahoo.com.au>
Reviewed-by: Brian Paul <brianp@vmware.com>
src/mesa/main/errors.c
src/mesa/main/errors.h
src/mesa/main/mtypes.h

index 8e97b524614c3e3d8cefef548035205f49e35ad0..afe1affcf99c87f849f44ec1ed9dffa5180ecd2a 100644 (file)
@@ -189,8 +189,9 @@ 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[source][type];
+         &ctx->Debug.Namespaces[gstack][source][type];
    uintptr_t state;
 
    /* In addition to not being able to store zero as a value, HashTable also
@@ -206,7 +207,7 @@ should_log(struct gl_context *ctx,
       struct gl_debug_severity *entry;
 
       if (state == NOT_FOUND) {
-         if (ctx->Debug.Defaults[severity][source][type])
+         if (ctx->Debug.Defaults[gstack][severity][source][type])
             state = ENABLED;
          else
             state = DISABLED;
@@ -240,8 +241,9 @@ 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[source][type];
+         &ctx->Debug.Namespaces[gstack][source][type];
    uintptr_t state;
 
    /* In addition to not being able to store zero as a value, HashTable also
@@ -266,6 +268,39 @@ set_message_state(struct gl_context *ctx,
       nspace->ZeroID = state;
 }
 
+static void
+store_message_details(struct gl_debug_msg *emptySlot,
+                      enum mesa_debug_source source,
+                      enum mesa_debug_type type, GLuint id,
+                      enum mesa_debug_severity severity, GLint len,
+                      const char *buf)
+{
+   assert(!emptySlot->message && !emptySlot->length);
+
+   emptySlot->message = malloc(len+1);
+   if (emptySlot->message) {
+      (void) strncpy(emptySlot->message, buf, (size_t)len);
+      emptySlot->message[len] = '\0';
+
+      emptySlot->length = len+1;
+      emptySlot->source = source;
+      emptySlot->type = type;
+      emptySlot->id = id;
+      emptySlot->severity = severity;
+   } else {
+      static GLuint oom_msg_id = 0;
+      debug_get_id(&oom_msg_id);
+
+      /* malloc failed! */
+      emptySlot->message = out_of_memory;
+      emptySlot->length = strlen(out_of_memory)+1;
+      emptySlot->source = MESA_DEBUG_SOURCE_OTHER;
+      emptySlot->type = MESA_DEBUG_TYPE_ERROR;
+      emptySlot->id = oom_msg_id;
+      emptySlot->severity = MESA_DEBUG_SEVERITY_HIGH;
+   }
+}
+
 /**
  * 'buf' is not necessarily a null-terminated string. When logging, copy
  * 'len' characters from it, store them in a new, null-terminated string,
@@ -301,30 +336,7 @@ _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
                           % MAX_DEBUG_LOGGED_MESSAGES;
    emptySlot = &ctx->Debug.Log[nextEmpty];
 
-   assert(!emptySlot->message && !emptySlot->length);
-
-   emptySlot->message = malloc(len+1);
-   if (emptySlot->message) {
-      (void) strncpy(emptySlot->message, buf, (size_t)len);
-      emptySlot->message[len] = '\0';
-
-      emptySlot->length = len+1;
-      emptySlot->source = source;
-      emptySlot->type = type;
-      emptySlot->id = id;
-      emptySlot->severity = severity;
-   } else {
-      static GLuint oom_msg_id = 0;
-      debug_get_id(&oom_msg_id);
-
-      /* malloc failed! */
-      emptySlot->message = out_of_memory;
-      emptySlot->length = strlen(out_of_memory)+1;
-      emptySlot->source = MESA_DEBUG_SOURCE_OTHER;
-      emptySlot->type = MESA_DEBUG_TYPE_ERROR;
-      emptySlot->id = oom_msg_id;
-      emptySlot->severity = MESA_DEBUG_SEVERITY_HIGH;
-   }
+   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;
@@ -486,6 +498,7 @@ control_messages(struct gl_context *ctx,
                  GLboolean enabled)
 {
    int s, t, sev, smax, tmax, sevmax;
+   GLint gstack = ctx->Debug.GroupStackDepth;
 
    if (source == MESA_DEBUG_SOURCE_COUNT) {
       source = 0;
@@ -515,10 +528,10 @@ control_messages(struct gl_context *ctx,
             struct gl_debug_severity *entry;
 
             /* change the default for IDs we've never seen before. */
-            ctx->Debug.Defaults[sev][s][t] = enabled;
+            ctx->Debug.Defaults[gstack][sev][s][t] = enabled;
 
             /* Now change the state of IDs we *have* seen... */
-            foreach(node, &ctx->Debug.Namespaces[s][t].Severity[sev]) {
+            foreach(node, &ctx->Debug.Namespaces[gstack][s][t].Severity[sev]) {
                entry = (struct gl_debug_severity *)node;
                set_message_state(ctx, s, t, entry->ID, enabled);
             }
@@ -594,19 +607,17 @@ message_control(GLenum gl_source, GLenum gl_type,
 }
 
 /**
- * This is a generic message insert function for use by both
- * glDebugMessageInsertARB and glDebugMessageInsert.
+ * This is a generic message insert function.
+ * Validation of source, type and severity parameters should be done
+ * before calling this funtion.
  */
 static void
 message_insert(GLenum source, GLenum type, GLuint id,
                GLenum severity, GLint length, const GLchar* buf,
-               unsigned caller, const char *callerstr)
+               const char *callerstr)
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   if (!validate_params(ctx, caller, callerstr, source, type, severity))
-      return; /* GL_INVALID_ENUM */
-
    if (length < 0)
       length = strlen(buf);
 
@@ -677,6 +688,37 @@ 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,
@@ -684,8 +726,13 @@ _mesa_DebugMessageInsert(GLenum source, GLenum type, GLuint id,
 {
    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,
-                  INSERT, callerstr);
+                  callerstr);
 }
 
 GLuint GLAPIENTRY
@@ -722,13 +769,112 @@ void GLAPIENTRY
 _mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
                      const GLchar *message)
 {
+   const char *callerstr = "glPushDebugGroup";
+   int s, t, sev;
+   GLint prevStackDepth;
+   GLint currStackDepth;
+   struct gl_debug_msg *emptySlot;
+
+   GET_CURRENT_CONTEXT(ctx);
 
+   if (ctx->Debug.GroupStackDepth >= MAX_DEBUG_GROUP_STACK_DEPTH-1) {
+      _mesa_error(ctx, GL_STACK_OVERFLOW, "%s", callerstr);
+      return;
+   }
+
+   switch(source) {
+   case GL_DEBUG_SOURCE_APPLICATION:
+   case GL_DEBUG_SOURCE_THIRD_PARTY:
+      break;
+   default:
+      _mesa_error(ctx, GL_INVALID_ENUM, "bad value passed to %s"
+                  "(source=0x%x)", callerstr, source);
+      return;
+   }
+
+   message_insert(source, GL_DEBUG_TYPE_PUSH_GROUP, id,
+                  GL_DEBUG_SEVERITY_NOTIFICATION, length,
+                  message, callerstr);
+
+   prevStackDepth = ctx->Debug.GroupStackDepth;
+   ctx->Debug.GroupStackDepth++;
+   currStackDepth = ctx->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];
+   store_message_details(emptySlot, gl_enum_to_debug_source(source),
+                         gl_enum_to_debug_source(GL_DEBUG_TYPE_PUSH_GROUP),
+                         id,
+                   gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
+                         length, message);
+
+   /* 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 (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);
+
+         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];
+
+            /* 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]) {
+               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);
+            }
+         }
+      }
 }
 
 void GLAPIENTRY
 _mesa_PopDebugGroup()
 {
+   const char *callerstr = "glPopDebugGroup";
+   struct gl_debug_msg *gdmessage;
+   GLint prevStackDepth;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (ctx->Debug.GroupStackDepth <= 0) {
+      _mesa_error(ctx, GL_STACK_UNDERFLOW, "%s", callerstr);
+      return;
+   }
+
+   prevStackDepth = ctx->Debug.GroupStackDepth;
+   ctx->Debug.GroupStackDepth--;
 
+   gdmessage = &ctx->Debug.DebugGroupMsgs[prevStackDepth];
+   /* using _mesa_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);
+
+   if (gdmessage->message != (char*)out_of_memory)
+      free(gdmessage->message);
+   gdmessage->message = NULL;
+   gdmessage->length = 0;
+
+   /* free popped debug group data */
+   free_errors_data(ctx, prevStackDepth);
 }
 
 void GLAPIENTRY
@@ -738,8 +884,13 @@ _mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
 {
    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,
-                  INSERT_ARB, callerstr);
+                  callerstr);
 }
 
 GLuint GLAPIENTRY
@@ -784,53 +935,39 @@ _mesa_init_errors(struct gl_context *ctx)
    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[MESA_DEBUG_SEVERITY_HIGH], GL_TRUE,
-          sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH]);
-   memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE,
-          sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM]);
-   memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW], GL_FALSE,
-          sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW]);
+   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[s][t].IDs = _mesa_NewHashTable();
-         assert(ctx->Debug.Namespaces[s][t].IDs);
+         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[s][t].Severity[sev]);
+            make_empty_list(&ctx->Debug.Namespaces[0][s][t].Severity[sev]);
       }
 }
 
-static void
-do_nothing(GLuint key, void *data, void *userData)
-{
-}
-
+/**
+ * Loop through debug group stack tearing down states for
+ * filtering debug messages.
+ */
 void
 _mesa_free_errors_data(struct gl_context *ctx)
 {
-   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[s][t].IDs, do_nothing, NULL);
-         _mesa_DeleteHashTable(ctx->Debug.Namespaces[s][t].IDs);
-         for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
-            struct simple_node *node, *tmp;
-            struct gl_debug_severity *entry;
+   GLint i;
 
-            foreach_s(node, tmp, &ctx->Debug.Namespaces[s][t].Severity[sev]) {
-               entry = (struct gl_debug_severity *)node;
-               free(entry);
-            }
-         }
-      }
+   for (i = 0; i <= ctx->Debug.GroupStackDepth; i++) {
+      free_errors_data(ctx, i);
+   }
 }
 
 /**********************************************************************/
index ff6f5c69c0875608d329248bb8c87181fdaf696a..a837dc8e1b07c765f42b3cfc1eedde8e5b5d175b 100644 (file)
@@ -117,6 +117,11 @@ _mesa_DebugMessageControl(GLenum source, GLenum type, GLenum severity,
 void GLAPIENTRY
 _mesa_DebugMessageCallback(GLDEBUGPROC callback,
                            const void *userParam);
+void GLAPIENTRY
+_mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
+                     const GLchar *message);
+void GLAPIENTRY
+_mesa_PopDebugGroup(void);
 
 #ifdef __cplusplus
 }
index 5fafaa6cd73a1788798beb4359b2c242b5a8a36b..0aef5d5bd364d4c51944976f0192248c73f1edb0 100644 (file)
@@ -3380,9 +3380,10 @@ struct gl_debug_state
    GLDEBUGPROC Callback;
    const void *CallbackData;
    GLboolean SyncOutput;
-   GLboolean Defaults[MESA_DEBUG_SEVERITY_COUNT][MESA_DEBUG_SOURCE_COUNT][MESA_DEBUG_TYPE_COUNT];
-   struct gl_debug_namespace Namespaces[MESA_DEBUG_SOURCE_COUNT][MESA_DEBUG_TYPE_COUNT];
+   GLboolean Defaults[MAX_DEBUG_GROUP_STACK_DEPTH][MESA_DEBUG_SEVERITY_COUNT][MESA_DEBUG_SOURCE_COUNT][MESA_DEBUG_TYPE_COUNT];
+   struct gl_debug_namespace Namespaces[MAX_DEBUG_GROUP_STACK_DEPTH][MESA_DEBUG_SOURCE_COUNT][MESA_DEBUG_TYPE_COUNT];
    struct gl_debug_msg Log[MAX_DEBUG_LOGGED_MESSAGES];
+   struct gl_debug_msg DebugGroupMsgs[MAX_DEBUG_GROUP_STACK_DEPTH];
    GLint GroupStackDepth;
    GLint NumMessages;
    GLint NextMsg;