X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ferrors.c;h=aa0ff50ac3742df9e80ceadf3664c51150d09b14;hb=637b6c24785d202e0f608c8dec098d63d857ae0e;hp=20d8d6019c0f87c2a1cba6e3786f3c700de36dd6;hpb=a30c4c6ca018413db8f8ca5c766a6f0d3f8af6be;p=mesa.git diff --git a/src/mesa/main/errors.c b/src/mesa/main/errors.c index 20d8d6019c0..aa0ff50ac37 100644 --- a/src/mesa/main/errors.c +++ b/src/mesa/main/errors.c @@ -41,20 +41,22 @@ static mtx_t DynamicIDMutex = _MTX_INITIALIZER_NP; static GLuint NextDynamicID = 1; -struct gl_debug_severity +/** + * A namespace element. + */ +struct gl_debug_element { struct simple_node link; + GLuint ID; + /* at which severity levels (mesa_debug_severity) is the message enabled */ + GLbitfield State; }; struct gl_debug_namespace { - struct _mesa_HashTable *IDs; - unsigned ZeroID; /* a HashTable won't take zero, so store its state here */ - /** lists of IDs in the hash table at each severity */ - struct simple_node Severity[MESA_DEBUG_SEVERITY_COUNT]; - - GLboolean Defaults[MESA_DEBUG_SEVERITY_COUNT]; + struct simple_node Elements; + GLbitfield DefaultState; }; struct gl_debug_group { @@ -91,7 +93,7 @@ struct gl_debug_state GLboolean SyncOutput; GLboolean DebugOutput; - struct gl_debug_group Groups[MAX_DEBUG_GROUP_STACK_DEPTH]; + struct gl_debug_group *Groups[MAX_DEBUG_GROUP_STACK_DEPTH]; struct gl_debug_message GroupMessages[MAX_DEBUG_GROUP_STACK_DEPTH]; GLint GroupStackDepth; @@ -190,48 +192,6 @@ debug_get_id(GLuint *id) } } - -/* - * We store a bitfield in the hash table, with five possible values total. - * - * The ENABLED_BIT's purpose is self-explanatory. - * - * The FOUND_BIT is needed to differentiate the value of DISABLED from - * the value returned by HashTableLookup() when it can't find the given key. - * - * The KNOWN_SEVERITY bit is a bit complicated: - * - * A client may call Control() with an array of IDs, then call Control() - * on all message IDs of a certain severity, then Insert() one of the - * previously specified IDs, giving us a known severity level, then call - * Control() on all message IDs of a certain severity level again. - * - * After the first call, those IDs will have a FOUND_BIT, but will not - * exist in any severity-specific list, so the second call will not - * impact them. This is undesirable but unavoidable given the API: - * The only entrypoint that gives a severity for a client-defined ID - * is the Insert() call. - * - * For the sake of Control(), we want to maintain the invariant - * that an ID will either appear in none of the three severity lists, - * or appear once, to minimize pointless duplication and potential surprises. - * - * Because Insert() is the only place that will learn an ID's severity, - * it should insert an ID into the appropriate list, but only if the ID - * doesn't exist in it or any other list yet. Because searching all three - * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY. - */ -enum { - FOUND_BIT = 1 << 0, - ENABLED_BIT = 1 << 1, - KNOWN_SEVERITY = 1 << 2, - - /* HashTable reserves zero as a return value meaning 'not found' */ - NOT_FOUND = 0, - DISABLED = FOUND_BIT, - ENABLED = ENABLED_BIT | FOUND_BIT -}; - static void debug_message_clear(struct gl_debug_message *msg) { @@ -277,84 +237,45 @@ debug_message_store(struct gl_debug_message *msg, static void debug_namespace_init(struct gl_debug_namespace *ns) { - int sev; - - memset(ns, 0, sizeof(*ns)); - - ns->IDs = _mesa_NewHashTable(); - assert(ns->IDs); - - for (sev = 0; sev < Elements(ns->Severity); sev++) - make_empty_list(&ns->Severity[sev]); + make_empty_list(&ns->Elements); /* Enable all the messages with severity HIGH or MEDIUM by default */ - ns->Defaults[MESA_DEBUG_SEVERITY_HIGH] = GL_TRUE; - ns->Defaults[MESA_DEBUG_SEVERITY_MEDIUM] = GL_TRUE; -} - -static void -debug_namespace_clear_cb(GLuint key, void *data, void *userData) -{ + ns->DefaultState = (1 << MESA_DEBUG_SEVERITY_HIGH) | + (1 << MESA_DEBUG_SEVERITY_MEDIUM); } static void debug_namespace_clear(struct gl_debug_namespace *ns) { - int sev; - - _mesa_HashDeleteAll(ns->IDs, debug_namespace_clear_cb, NULL); - _mesa_DeleteHashTable(ns->IDs); - - for (sev = 0; sev < Elements(ns->Severity); sev++) { - struct simple_node *node, *tmp; + struct simple_node *node, *tmp; - foreach_s(node, tmp, &ns->Severity[sev]) - free(node); - } + foreach_s(node, tmp, &ns->Elements) + free(node); } static bool debug_namespace_copy(struct gl_debug_namespace *dst, const struct gl_debug_namespace *src) { - bool err = false; - int sev; + struct simple_node *node; - /* copy id settings */ - dst->IDs = _mesa_HashClone(src->IDs); - if (!dst->IDs) - return false; + dst->DefaultState = src->DefaultState; - for (sev = 0; sev < Elements(dst->Severity); sev++) { - struct simple_node *node; + make_empty_list(&dst->Elements); + foreach(node, &src->Elements) { + const struct gl_debug_element *elem = + (const struct gl_debug_element *) node; + struct gl_debug_element *copy; - /* copy default settings for unknown ids */ - dst->Defaults[sev] = src->Defaults[sev]; - - make_empty_list(&dst->Severity[sev]); - if (err) - continue; - - /* copy known id severity settings */ - foreach(node, &src->Severity[sev]) { - const struct gl_debug_severity *entry = - (const struct gl_debug_severity *) node; - struct gl_debug_severity *copy; - - copy = malloc(sizeof(*copy)); - if (!copy) { - err = true; - break; - } - - copy->ID = entry->ID; - insert_at_tail(&dst->Severity[sev], ©->link); + copy = malloc(sizeof(*copy)); + if (!copy) { + debug_namespace_clear(dst); + return false; } - } - if (err) { - debug_namespace_clear(dst); - return false; + copy->ID = elem->ID; + copy->State = elem->State; + insert_at_tail(&dst->Elements, ©->link); } return true; @@ -367,29 +288,39 @@ static bool debug_namespace_set(struct gl_debug_namespace *ns, GLuint id, bool enabled) { - uintptr_t state; + const uint32_t state = (enabled) ? + ((1 << MESA_DEBUG_SEVERITY_COUNT) - 1) : 0; + struct gl_debug_element *elem = NULL; + struct simple_node *node; + + /* find the element */ + foreach(node, &ns->Elements) { + struct gl_debug_element *tmp = (struct gl_debug_element *) node; + if (tmp->ID == id) { + elem = tmp; + break; + } + } - /* 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(ns->IDs, id); - else - state = ns->ZeroID; + /* we do not need the element if it has the default state */ + if (ns->DefaultState == state) { + if (elem) { + remove_from_list(&elem->link); + free(elem); + } + return true; + } - if (state == NOT_FOUND) - state = enabled ? ENABLED : DISABLED; - else { - if (enabled) - state |= ENABLED_BIT; - else - state &= ~ENABLED_BIT; + if (!elem) { + elem = malloc(sizeof(*elem)); + if (!elem) + return false; + + elem->ID = id; + insert_at_tail(&ns->Elements, &elem->link); } - if (id) - _mesa_HashInsert(ns->IDs, id, (void *) state); - else - ns->ZeroID = state; + elem->State = state; return true; } @@ -404,26 +335,29 @@ debug_namespace_set_all(struct gl_debug_namespace *ns, enum mesa_debug_severity severity, bool enabled) { - int sev, end; - - if (severity >= Elements(ns->Severity)) { - end = severity; - severity = 0; - } else { - end = severity + 1; + struct simple_node *node, *tmp; + uint32_t mask, val; + + /* set all elements to the same state */ + if (severity == MESA_DEBUG_SEVERITY_COUNT) { + ns->DefaultState = (enabled) ? ((1 << severity) - 1) : 0; + debug_namespace_clear(ns); + make_empty_list(&ns->Elements); + return; } - for (sev = severity; sev < end; sev++) { - struct simple_node *node; - struct gl_debug_severity *entry; + mask = 1 << severity; + val = (enabled) ? mask : 0; + + ns->DefaultState = (ns->DefaultState & ~mask) | val; - /* change the default for IDs we've never seen before. */ - ns->Defaults[sev] = enabled; + foreach_s(node, tmp, &ns->Elements) { + struct gl_debug_element *elem = (struct gl_debug_element *) node; - /* Now change the state of IDs we *have* seen... */ - foreach(node, &ns->Severity[sev]) { - entry = (struct gl_debug_severity *) node; - debug_namespace_set(ns, entry->ID, enabled); + elem->State = (elem->State & ~mask) | val; + if (elem->State == ns->DefaultState) { + remove_from_list(node); + free(node); } } } @@ -432,47 +366,23 @@ debug_namespace_set_all(struct gl_debug_namespace *ns, * Get the state of \p id in the namespace. */ static bool -debug_namespace_get(struct gl_debug_namespace *ns, GLuint id, +debug_namespace_get(const struct gl_debug_namespace *ns, GLuint id, enum mesa_debug_severity severity) { - uintptr_t state = 0; - - /* 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(ns->IDs, id); - else - state = ns->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 (ns->Defaults[severity]) - state = ENABLED; - else - state = DISABLED; - } - - entry = malloc(sizeof *entry); - if (entry) { - state |= KNOWN_SEVERITY; + struct simple_node *node; + uint32_t state; - if (id) - _mesa_HashInsert(ns->IDs, id, (void *) state); - else - ns->ZeroID = state; + state = ns->DefaultState; + foreach(node, &ns->Elements) { + struct gl_debug_element *elem = (struct gl_debug_element *) node; - entry->ID = id; - insert_at_tail(&ns->Severity[severity], &entry->link); + if (elem->ID == id) { + state = elem->State; + break; } } - return (state & ENABLED_BIT); + return (state & (1 << severity)); } /** @@ -488,32 +398,92 @@ debug_create(void) if (!debug) return NULL; + debug->Groups[0] = malloc(sizeof(*debug->Groups[0])); + if (!debug->Groups[0]) { + free(debug); + return NULL; + } + /* 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_namespace_init(&debug->Groups[0].Namespaces[s][t]); - } + for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) + debug_namespace_init(&debug->Groups[0]->Namespaces[s][t]); } return debug; } /** - * Free debug state for the given stack depth. + * Return true if the top debug group points to the group below it. */ -static void -debug_clear_group(struct gl_debug_state *debug, GLint gstack) +static bool +debug_is_group_read_only(const struct gl_debug_state *debug) +{ + const GLint gstack = debug->GroupStackDepth; + return (gstack > 0 && debug->Groups[gstack] == debug->Groups[gstack - 1]); +} + +/** + * Make the top debug group writable. + */ +static bool +debug_make_group_writable(struct gl_debug_state *debug) { - struct gl_debug_group *grp = &debug->Groups[gstack]; - enum mesa_debug_type t; - enum mesa_debug_source s; + const GLint gstack = debug->GroupStackDepth; + const struct gl_debug_group *src = debug->Groups[gstack]; + struct gl_debug_group *dst; + int s, t; + + if (!debug_is_group_read_only(debug)) + return true; + + dst = malloc(sizeof(*dst)); + if (!dst) + return false; - /* 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++) { - debug_namespace_clear(&grp->Namespaces[s][t]); + if (!debug_namespace_copy(&dst->Namespaces[s][t], + &src->Namespaces[s][t])) { + /* error path! */ + for (t = t - 1; t >= 0; t--) + debug_namespace_clear(&dst->Namespaces[s][t]); + for (s = s - 1; s >= 0; s--) { + for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) + debug_namespace_clear(&dst->Namespaces[s][t]); + } + free(dst); + return false; + } } } + + debug->Groups[gstack] = dst; + + return true; +} + +/** + * Free the top debug group. + */ +static void +debug_clear_group(struct gl_debug_state *debug) +{ + const GLint gstack = debug->GroupStackDepth; + + if (!debug_is_group_read_only(debug)) { + struct gl_debug_group *grp = debug->Groups[gstack]; + int s, t; + + for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) { + for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) + debug_namespace_clear(&grp->Namespaces[s][t]); + } + + free(grp); + } + + debug->Groups[gstack] = NULL; } /** @@ -523,11 +493,12 @@ debug_clear_group(struct gl_debug_state *debug, GLint gstack) static void debug_destroy(struct gl_debug_state *debug) { - GLint i; - - for (i = 0; i <= debug->GroupStackDepth; i++) - debug_clear_group(debug, i); + while (debug->GroupStackDepth > 0) { + debug_clear_group(debug); + debug->GroupStackDepth--; + } + debug_clear_group(debug); free(debug); } @@ -541,10 +512,12 @@ debug_set_message_enable(struct gl_debug_state *debug, GLuint id, GLboolean enabled) { const GLint gstack = debug->GroupStackDepth; - struct gl_debug_namespace *nspace = - &debug->Groups[gstack].Namespaces[source][type]; + struct gl_debug_namespace *ns; - debug_namespace_set(nspace, id, enabled); + debug_make_group_writable(debug); + ns = &debug->Groups[gstack]->Namespaces[source][type]; + + debug_namespace_set(ns, id, enabled); } /* @@ -582,10 +555,12 @@ debug_set_message_enable_all(struct gl_debug_state *debug, tmax = type+1; } + debug_make_group_writable(debug); + for (s = source; s < smax; s++) { for (t = type; t < tmax; t++) { struct gl_debug_namespace *nspace = - &debug->Groups[gstack].Namespaces[s][t]; + &debug->Groups[gstack]->Namespaces[s][t]; debug_namespace_set_all(nspace, severity, enabled); } } @@ -595,14 +570,14 @@ debug_set_message_enable_all(struct gl_debug_state *debug, * Returns if the given message source/type/ID tuple is enabled. */ static bool -debug_is_message_enabled(struct gl_debug_state *debug, +debug_is_message_enabled(const struct gl_debug_state *debug, enum mesa_debug_source source, enum mesa_debug_type type, GLuint id, enum mesa_debug_severity severity) { const GLint gstack = debug->GroupStackDepth; - struct gl_debug_group *grp = &debug->Groups[gstack]; + struct gl_debug_group *grp = debug->Groups[gstack]; struct gl_debug_namespace *nspace = &grp->Namespaces[source][type]; if (!debug->DebugOutput) @@ -686,34 +661,17 @@ static void debug_push_group(struct gl_debug_state *debug) { const GLint gstack = debug->GroupStackDepth; - int s, t; - /* 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++) { - const struct gl_debug_namespace *nspace = - &debug->Groups[gstack].Namespaces[s][t]; - struct gl_debug_namespace *next = - &debug->Groups[gstack + 1].Namespaces[s][t]; - - if (!debug_namespace_copy(next, nspace)) - goto out; - } - } - -out: + /* just point to the previous stack */ + debug->Groups[gstack + 1] = debug->Groups[gstack]; debug->GroupStackDepth++; } static void debug_pop_group(struct gl_debug_state *debug) { - const GLint gstack = debug->GroupStackDepth; - + debug_clear_group(debug); debug->GroupStackDepth--; - debug_clear_group(debug, gstack); } @@ -1456,6 +1414,12 @@ _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) _mesa_record_error(ctx, error); } +void +_mesa_error_no_memory(const char *caller) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller); +} /** * Report debug information. Print error message to stderr via fprintf().