aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/main/errors.c
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/main/errors.c')
-rw-r--r--mesalib/src/mesa/main/errors.c633
1 files changed, 470 insertions, 163 deletions
diff --git a/mesalib/src/mesa/main/errors.c b/mesalib/src/mesa/main/errors.c
index cc93d3bd6..e1a9fe2f5 100644
--- a/mesalib/src/mesa/main/errors.c
+++ b/mesalib/src/mesa/main/errors.c
@@ -39,6 +39,9 @@
#include "hash_table.h"
#include "glapi/glthread.h"
+#define MESSAGE_LOG 1
+#define MESSAGE_LOG_ARB 2
+
_glthread_DECLARE_STATIC_MUTEX(DynamicIDMutex);
static GLuint NextDynamicID = 1;
@@ -66,12 +69,16 @@ static const GLenum debug_type_enums[] = {
GL_DEBUG_TYPE_PORTABILITY,
GL_DEBUG_TYPE_PERFORMANCE,
GL_DEBUG_TYPE_OTHER,
+ GL_DEBUG_TYPE_MARKER,
+ GL_DEBUG_TYPE_PUSH_GROUP,
+ GL_DEBUG_TYPE_POP_GROUP,
};
static const GLenum debug_severity_enums[] = {
GL_DEBUG_SEVERITY_LOW,
GL_DEBUG_SEVERITY_MEDIUM,
GL_DEBUG_SEVERITY_HIGH,
+ GL_DEBUG_SEVERITY_NOTIFICATION,
};
static enum mesa_debug_source
@@ -185,10 +192,14 @@ 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;
+ if (!ctx->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)
@@ -202,7 +213,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;
@@ -236,8 +247,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
@@ -262,6 +274,71 @@ 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;
+ }
+}
+
+ /**
+ * 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
* 'len' characters from it, store them in a new, null-terminated string,
@@ -282,10 +359,17 @@ _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
return;
if (ctx->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],
- debug_type_enums[type],
+ gl_type,
id,
- debug_severity_enums[severity],
+ gl_severity,
len, buf, ctx->Debug.CallbackData);
return;
}
@@ -297,30 +381,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;
@@ -340,7 +401,8 @@ _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
*/
static GLsizei
_mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
- GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
+ GLuint *id, GLenum *severity, GLsizei bufSize, char *buf,
+ unsigned caller)
{
struct gl_debug_msg *msg;
GLsizei length;
@@ -356,12 +418,18 @@ _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
if (bufSize < length && buf != NULL)
return 0;
- if (severity)
+ if (severity) {
*severity = debug_severity_enums[msg->severity];
+ if (caller == MESSAGE_LOG_ARB)
+ *severity = remap_severity(*severity);
+ }
if (source)
*source = debug_source_enums[msg->source];
- if (type)
+ if (type) {
*type = debug_type_enums[msg->type];
+ if (caller == MESSAGE_LOG_ARB)
+ *type = remap_type(*type);
+ }
if (id)
*id = msg->id;
@@ -388,13 +456,19 @@ _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
* 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
*/
static GLboolean
validate_params(struct gl_context *ctx, unsigned caller,
- GLenum source, GLenum type, GLenum severity)
+ const char *callerstr, GLenum source, GLenum type,
+ GLenum severity)
{
#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:
@@ -403,10 +477,10 @@ 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)
+ if (caller != INSERT || caller == INSERT_ARB)
break;
case GL_DONT_CARE:
- if (caller == CONTROL)
+ if (caller == CONTROL || caller == CONTROL_ARB)
break;
default:
goto error;
@@ -420,8 +494,12 @@ validate_params(struct gl_context *ctx, unsigned caller,
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;
case GL_DONT_CARE:
- if (caller == CONTROL)
+ if (caller == CONTROL || caller == CONTROL_ARB)
break;
default:
goto error;
@@ -432,8 +510,12 @@ validate_params(struct gl_context *ctx, unsigned caller,
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;
case GL_DONT_CARE:
- if (caller == CONTROL)
+ if (caller == CONTROL || caller == CONTROL_ARB)
break;
default:
goto error;
@@ -442,93 +524,13 @@ validate_params(struct gl_context *ctx, unsigned caller,
error:
{
- const char *callerstr;
- if (caller == INSERT)
- callerstr = "glDebugMessageInsertARB";
- else if (caller == CONTROL)
- callerstr = "glDebugMessageControlARB";
- else
- return GL_FALSE;
-
- _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s"
+ _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;
}
-void GLAPIENTRY
-_mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
- GLenum severity, GLint length,
- const GLcharARB* buf)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if (!validate_params(ctx, INSERT, source, type, severity))
- return; /* GL_INVALID_ENUM */
-
- if (length < 0)
- length = strlen(buf);
-
- if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB"
- "(length=%d, which is not less than "
- "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length,
- MAX_DEBUG_MESSAGE_LENGTH);
- 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);
-}
-
-GLuint GLAPIENTRY
-_mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
- GLenum* types, GLenum* ids, GLenum* severities,
- GLsizei* lengths, GLcharARB* messageLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint ret;
-
- if (!messageLog)
- logSize = 0;
-
- if (logSize < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB"
- "(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);
- if (!written)
- break;
-
- if (messageLog) {
- messageLog += written;
- logSize -= written;
- }
- if (lengths) {
- *lengths = written;
- lengths++;
- }
-
- if (severities)
- severities++;
- if (sources)
- sources++;
- if (types)
- types++;
- if (ids)
- ids++;
- }
-
- return ret;
-}
-
/**
* Set the state of all message IDs found in the given intersection of
* 'source', 'type', and 'severity'. The _COUNT enum can be used for
@@ -548,6 +550,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;
@@ -577,10 +580,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);
}
@@ -618,28 +621,36 @@ control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
control_messages(ctx, source, type, severity, enabled);
}
-void GLAPIENTRY
-_mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type,
- GLenum gl_severity,
- GLsizei count, const GLuint *ids,
- GLboolean 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, "glDebugMessageControlARB"
- "(count=%d : count must not be negative)", count);
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(count=%d : count must not be negative)", callerstr,
+ count);
return;
}
- if (!validate_params(ctx, CONTROL, gl_source, gl_type, gl_severity))
+ 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, "glDebugMessageControlARB"
- "(When passing an array of ids, severity must be"
- " GL_DONT_CARE, and source and type must not be 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;
}
@@ -647,43 +658,84 @@ _mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type,
count, ids, enabled);
}
-void GLAPIENTRY
-_mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const void *userParam)
+/**
+ * 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,
+ const char *callerstr)
{
GET_CURRENT_CONTEXT(ctx);
- ctx->Debug.Callback = callback;
- ctx->Debug.CallbackData = userParam;
+
+ if (length < 0)
+ length = strlen(buf);
+
+ if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(length=%d, which is not less than "
+ "GL_MAX_DEBUG_MESSAGE_LENGTH=%d)", callerstr, length,
+ MAX_DEBUG_MESSAGE_LENGTH);
+ 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);
}
-void
-_mesa_init_errors(struct gl_context *ctx)
+/**
+ * This is a generic message insert function for use by both
+ * glGetDebugMessageLogARB and glGetDebugMessageLog.
+ */
+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)
{
- int s, t, sev;
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint ret;
- 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;
+ if (!messageLog)
+ logSize = 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]);
+ if (logSize < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(logSize=%d : logSize must not be negative)", callerstr,
+ logSize);
+ return 0;
+ }
- /* 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);
+ for (ret = 0; ret < count; ret++) {
+ GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
+ logSize, messageLog, caller);
+ if (!written)
+ break;
- for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++)
- make_empty_list(&ctx->Debug.Namespaces[s][t].Severity[sev]);
+ if (messageLog) {
+ messageLog += written;
+ logSize -= written;
}
+ if (lengths) {
+ *lengths = written;
+ lengths++;
+ }
+
+ if (severities)
+ severities++;
+ if (sources)
+ sources++;
+ if (types)
+ types++;
+ if (ids)
+ ids++;
+ }
+
+ return ret;
}
static void
@@ -691,8 +743,8 @@ do_nothing(GLuint key, void *data, void *userData)
{
}
-void
-_mesa_free_errors_data(struct gl_context *ctx)
+static void
+free_errors_data(struct gl_context *ctx, GLint gstack)
{
enum mesa_debug_type t;
enum mesa_debug_source s;
@@ -701,13 +753,15 @@ _mesa_free_errors_data(struct gl_context *ctx)
/* 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);
+ _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[s][t].Severity[sev]) {
+ foreach_s(node, tmp,
+ &ctx->Debug.Namespaces[gstack][s][t].Severity[sev]) {
entry = (struct gl_debug_severity *)node;
free(entry);
}
@@ -715,6 +769,259 @@ _mesa_free_errors_data(struct gl_context *ctx)
}
}
+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)
+{
+ const char *callerstr = "glGetDebugMessageLog";
+
+ return get_message_log(count, logSize, sources, types, ids, severities,
+ lengths, messageLog, MESSAGE_LOG, callerstr);
+}
+
+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;
+}
+
+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
+_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]);
+ }
+}
+
+/**
+ * Loop through debug group stack tearing down states for
+ * filtering debug messages.
+ */
+void
+_mesa_free_errors_data(struct gl_context *ctx)
+{
+ GLint i;
+
+ for (i = 0; i <= ctx->Debug.GroupStackDepth; i++) {
+ free_errors_data(ctx, i);
+ }
+}
+
/**********************************************************************/
/** \name Diagnostics */
/*@{*/