mesa: make _mesa_lookup_list() non-static
[mesa.git] / src / mesa / main / errors.c
1 /**
2 * \file errors.c
3 * Mesa debugging and error handling functions.
4 */
5
6 /*
7 * Mesa 3-D graphics library
8 *
9 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30
31 #include "errors.h"
32 #include "enums.h"
33 #include "imports.h"
34 #include "context.h"
35 #include "dispatch.h"
36 #include "hash.h"
37 #include "mtypes.h"
38 #include "version.h"
39 #include "hash_table.h"
40 #include "glapi/glthread.h"
41
42 _glthread_DECLARE_STATIC_MUTEX(DynamicIDMutex);
43 static GLuint NextDynamicID = 1;
44
45 struct gl_debug_severity
46 {
47 struct simple_node link;
48 GLuint ID;
49 };
50
51 static char out_of_memory[] = "Debugging error: out of memory";
52
53 static const GLenum debug_source_enums[] = {
54 GL_DEBUG_SOURCE_API,
55 GL_DEBUG_SOURCE_WINDOW_SYSTEM,
56 GL_DEBUG_SOURCE_SHADER_COMPILER,
57 GL_DEBUG_SOURCE_THIRD_PARTY,
58 GL_DEBUG_SOURCE_APPLICATION,
59 GL_DEBUG_SOURCE_OTHER,
60 };
61
62 static const GLenum debug_type_enums[] = {
63 GL_DEBUG_TYPE_ERROR,
64 GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
65 GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
66 GL_DEBUG_TYPE_PORTABILITY,
67 GL_DEBUG_TYPE_PERFORMANCE,
68 GL_DEBUG_TYPE_OTHER,
69 GL_DEBUG_TYPE_MARKER,
70 GL_DEBUG_TYPE_PUSH_GROUP,
71 GL_DEBUG_TYPE_POP_GROUP,
72 };
73
74 static const GLenum debug_severity_enums[] = {
75 GL_DEBUG_SEVERITY_LOW,
76 GL_DEBUG_SEVERITY_MEDIUM,
77 GL_DEBUG_SEVERITY_HIGH,
78 GL_DEBUG_SEVERITY_NOTIFICATION,
79 };
80
81 static enum mesa_debug_source
82 gl_enum_to_debug_source(GLenum e)
83 {
84 int i;
85
86 for (i = 0; i < Elements(debug_source_enums); i++) {
87 if (debug_source_enums[i] == e)
88 break;
89 }
90 return i;
91 }
92
93 static enum mesa_debug_type
94 gl_enum_to_debug_type(GLenum e)
95 {
96 int i;
97
98 for (i = 0; i < Elements(debug_type_enums); i++) {
99 if (debug_type_enums[i] == e)
100 break;
101 }
102 return i;
103 }
104
105 static enum mesa_debug_severity
106 gl_enum_to_debug_severity(GLenum e)
107 {
108 int i;
109
110 for (i = 0; i < Elements(debug_severity_enums); i++) {
111 if (debug_severity_enums[i] == e)
112 break;
113 }
114 return i;
115 }
116
117 /**
118 * Handles generating a GL_ARB_debug_output message ID generated by the GL or
119 * GLSL compiler.
120 *
121 * The GL API has this "ID" mechanism, where the intention is to allow a
122 * client to filter in/out messages based on source, type, and ID. Of course,
123 * building a giant enum list of all debug output messages that Mesa might
124 * generate is ridiculous, so instead we have our caller pass us a pointer to
125 * static storage where the ID should get stored. This ID will be shared
126 * across all contexts for that message (which seems like a desirable
127 * property, even if it's not expected by the spec), but note that it won't be
128 * the same between executions if messages aren't generated in the same order.
129 */
130 static void
131 debug_get_id(GLuint *id)
132 {
133 if (!(*id)) {
134 _glthread_LOCK_MUTEX(DynamicIDMutex);
135 if (!(*id))
136 *id = NextDynamicID++;
137 _glthread_UNLOCK_MUTEX(DynamicIDMutex);
138 }
139 }
140
141 /*
142 * We store a bitfield in the hash table, with five possible values total.
143 *
144 * The ENABLED_BIT's purpose is self-explanatory.
145 *
146 * The FOUND_BIT is needed to differentiate the value of DISABLED from
147 * the value returned by HashTableLookup() when it can't find the given key.
148 *
149 * The KNOWN_SEVERITY bit is a bit complicated:
150 *
151 * A client may call Control() with an array of IDs, then call Control()
152 * on all message IDs of a certain severity, then Insert() one of the
153 * previously specified IDs, giving us a known severity level, then call
154 * Control() on all message IDs of a certain severity level again.
155 *
156 * After the first call, those IDs will have a FOUND_BIT, but will not
157 * exist in any severity-specific list, so the second call will not
158 * impact them. This is undesirable but unavoidable given the API:
159 * The only entrypoint that gives a severity for a client-defined ID
160 * is the Insert() call.
161 *
162 * For the sake of Control(), we want to maintain the invariant
163 * that an ID will either appear in none of the three severity lists,
164 * or appear once, to minimize pointless duplication and potential surprises.
165 *
166 * Because Insert() is the only place that will learn an ID's severity,
167 * it should insert an ID into the appropriate list, but only if the ID
168 * doesn't exist in it or any other list yet. Because searching all three
169 * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
170 */
171 enum {
172 FOUND_BIT = 1 << 0,
173 ENABLED_BIT = 1 << 1,
174 KNOWN_SEVERITY = 1 << 2,
175
176 /* HashTable reserves zero as a return value meaning 'not found' */
177 NOT_FOUND = 0,
178 DISABLED = FOUND_BIT,
179 ENABLED = ENABLED_BIT | FOUND_BIT
180 };
181
182 /**
183 * Returns the state of the given message source/type/ID tuple.
184 */
185 static GLboolean
186 should_log(struct gl_context *ctx,
187 enum mesa_debug_source source,
188 enum mesa_debug_type type,
189 GLuint id,
190 enum mesa_debug_severity severity)
191 {
192 GLint gstack = ctx->Debug.GroupStackDepth;
193 struct gl_debug_namespace *nspace =
194 &ctx->Debug.Namespaces[gstack][source][type];
195 uintptr_t state;
196
197 /* In addition to not being able to store zero as a value, HashTable also
198 can't use zero as a key. */
199 if (id)
200 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
201 else
202 state = nspace->ZeroID;
203
204 /* Only do this once for each ID. This makes sure the ID exists in,
205 at most, one list, and does not pointlessly appear multiple times. */
206 if (!(state & KNOWN_SEVERITY)) {
207 struct gl_debug_severity *entry;
208
209 if (state == NOT_FOUND) {
210 if (ctx->Debug.Defaults[gstack][severity][source][type])
211 state = ENABLED;
212 else
213 state = DISABLED;
214 }
215
216 entry = malloc(sizeof *entry);
217 if (!entry)
218 goto out;
219
220 state |= KNOWN_SEVERITY;
221
222 if (id)
223 _mesa_HashInsert(nspace->IDs, id, (void*)state);
224 else
225 nspace->ZeroID = state;
226
227 entry->ID = id;
228 insert_at_tail(&nspace->Severity[severity], &entry->link);
229 }
230
231 out:
232 return !!(state & ENABLED_BIT);
233 }
234
235 /**
236 * Sets the state of the given message source/type/ID tuple.
237 */
238 static void
239 set_message_state(struct gl_context *ctx,
240 enum mesa_debug_source source,
241 enum mesa_debug_type type,
242 GLuint id, GLboolean enabled)
243 {
244 GLint gstack = ctx->Debug.GroupStackDepth;
245 struct gl_debug_namespace *nspace =
246 &ctx->Debug.Namespaces[gstack][source][type];
247 uintptr_t state;
248
249 /* In addition to not being able to store zero as a value, HashTable also
250 can't use zero as a key. */
251 if (id)
252 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
253 else
254 state = nspace->ZeroID;
255
256 if (state == NOT_FOUND)
257 state = enabled ? ENABLED : DISABLED;
258 else {
259 if (enabled)
260 state |= ENABLED_BIT;
261 else
262 state &= ~ENABLED_BIT;
263 }
264
265 if (id)
266 _mesa_HashInsert(nspace->IDs, id, (void*)state);
267 else
268 nspace->ZeroID = state;
269 }
270
271 static void
272 store_message_details(struct gl_debug_msg *emptySlot,
273 enum mesa_debug_source source,
274 enum mesa_debug_type type, GLuint id,
275 enum mesa_debug_severity severity, GLint len,
276 const char *buf)
277 {
278 assert(!emptySlot->message && !emptySlot->length);
279
280 emptySlot->message = malloc(len+1);
281 if (emptySlot->message) {
282 (void) strncpy(emptySlot->message, buf, (size_t)len);
283 emptySlot->message[len] = '\0';
284
285 emptySlot->length = len+1;
286 emptySlot->source = source;
287 emptySlot->type = type;
288 emptySlot->id = id;
289 emptySlot->severity = severity;
290 } else {
291 static GLuint oom_msg_id = 0;
292 debug_get_id(&oom_msg_id);
293
294 /* malloc failed! */
295 emptySlot->message = out_of_memory;
296 emptySlot->length = strlen(out_of_memory)+1;
297 emptySlot->source = MESA_DEBUG_SOURCE_OTHER;
298 emptySlot->type = MESA_DEBUG_TYPE_ERROR;
299 emptySlot->id = oom_msg_id;
300 emptySlot->severity = MESA_DEBUG_SEVERITY_HIGH;
301 }
302 }
303
304 /**
305 * 'buf' is not necessarily a null-terminated string. When logging, copy
306 * 'len' characters from it, store them in a new, null-terminated string,
307 * and remember the number of bytes used by that string, *including*
308 * the null terminator this time.
309 */
310 static void
311 _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
312 enum mesa_debug_type type, GLuint id,
313 enum mesa_debug_severity severity, GLint len, const char *buf)
314 {
315 GLint nextEmpty;
316 struct gl_debug_msg *emptySlot;
317
318 assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH);
319
320 if (!should_log(ctx, source, type, id, severity))
321 return;
322
323 if (ctx->Debug.Callback) {
324 ctx->Debug.Callback(debug_source_enums[source],
325 debug_type_enums[type],
326 id,
327 debug_severity_enums[severity],
328 len, buf, ctx->Debug.CallbackData);
329 return;
330 }
331
332 if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
333 return;
334
335 nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages)
336 % MAX_DEBUG_LOGGED_MESSAGES;
337 emptySlot = &ctx->Debug.Log[nextEmpty];
338
339 store_message_details(emptySlot, source, type, id, severity, len, buf);
340
341 if (ctx->Debug.NumMessages == 0)
342 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
343
344 ctx->Debug.NumMessages++;
345 }
346
347 /**
348 * Pop the oldest debug message out of the log.
349 * Writes the message string, including the null terminator, into 'buf',
350 * using up to 'bufSize' bytes. If 'bufSize' is too small, or
351 * if 'buf' is NULL, nothing is written.
352 *
353 * Returns the number of bytes written on success, or when 'buf' is NULL,
354 * the number that would have been written. A return value of 0
355 * indicates failure.
356 */
357 static GLsizei
358 _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
359 GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
360 {
361 struct gl_debug_msg *msg;
362 GLsizei length;
363
364 if (ctx->Debug.NumMessages == 0)
365 return 0;
366
367 msg = &ctx->Debug.Log[ctx->Debug.NextMsg];
368 length = msg->length;
369
370 assert(length > 0 && length == ctx->Debug.NextMsgLength);
371
372 if (bufSize < length && buf != NULL)
373 return 0;
374
375 if (severity)
376 *severity = debug_severity_enums[msg->severity];
377 if (source)
378 *source = debug_source_enums[msg->source];
379 if (type)
380 *type = debug_type_enums[msg->type];
381 if (id)
382 *id = msg->id;
383
384 if (buf) {
385 assert(msg->message[length-1] == '\0');
386 (void) strncpy(buf, msg->message, (size_t)length);
387 }
388
389 if (msg->message != (char*)out_of_memory)
390 free(msg->message);
391 msg->message = NULL;
392 msg->length = 0;
393
394 ctx->Debug.NumMessages--;
395 ctx->Debug.NextMsg++;
396 ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
397 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
398
399 return length;
400 }
401
402 /**
403 * Verify that source, type, and severity are valid enums.
404 * glDebugMessageInsertARB only accepts two values for 'source',
405 * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
406 * in any parameter, so handle those cases specially.
407 *
408 * There is also special cases for handling values available in
409 * GL_KHR_debug that are not avaliable in GL_ARB_debug_output
410 */
411 static GLboolean
412 validate_params(struct gl_context *ctx, unsigned caller,
413 const char *callerstr, GLenum source, GLenum type,
414 GLenum severity)
415 {
416 #define INSERT 1
417 #define CONTROL 2
418 #define INSERT_ARB 3
419 #define CONTROL_ARB 4
420 switch(source) {
421 case GL_DEBUG_SOURCE_APPLICATION_ARB:
422 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
423 break;
424 case GL_DEBUG_SOURCE_API_ARB:
425 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
426 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
427 case GL_DEBUG_SOURCE_OTHER_ARB:
428 if (caller != INSERT || caller == INSERT_ARB)
429 break;
430 case GL_DONT_CARE:
431 if (caller == CONTROL || caller == CONTROL_ARB)
432 break;
433 default:
434 goto error;
435 }
436
437 switch(type) {
438 case GL_DEBUG_TYPE_ERROR_ARB:
439 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
440 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
441 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
442 case GL_DEBUG_TYPE_PORTABILITY_ARB:
443 case GL_DEBUG_TYPE_OTHER_ARB:
444 break;
445 case GL_DEBUG_TYPE_MARKER:
446 /* this value is only valid for GL_KHR_debug functions */
447 if (caller == CONTROL || caller == INSERT)
448 break;
449 case GL_DONT_CARE:
450 if (caller == CONTROL || caller == CONTROL_ARB)
451 break;
452 default:
453 goto error;
454 }
455
456 switch(severity) {
457 case GL_DEBUG_SEVERITY_HIGH_ARB:
458 case GL_DEBUG_SEVERITY_MEDIUM_ARB:
459 case GL_DEBUG_SEVERITY_LOW_ARB:
460 break;
461 case GL_DEBUG_SEVERITY_NOTIFICATION:
462 /* this value is only valid for GL_KHR_debug functions */
463 if (caller == CONTROL || caller == INSERT)
464 break;
465 case GL_DONT_CARE:
466 if (caller == CONTROL || caller == CONTROL_ARB)
467 break;
468 default:
469 goto error;
470 }
471 return GL_TRUE;
472
473 error:
474 {
475 _mesa_error(ctx, GL_INVALID_ENUM, "bad values passed to %s"
476 "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
477 source, type, severity);
478 }
479 return GL_FALSE;
480 }
481
482 /**
483 * Set the state of all message IDs found in the given intersection of
484 * 'source', 'type', and 'severity'. The _COUNT enum can be used for
485 * GL_DONT_CARE (include all messages in the class).
486 *
487 * This requires both setting the state of all previously seen message
488 * IDs in the hash table, and setting the default state for all
489 * applicable combinations of source/type/severity, so that all the
490 * yet-unknown message IDs that may be used in the future will be
491 * impacted as if they were already known.
492 */
493 static void
494 control_messages(struct gl_context *ctx,
495 enum mesa_debug_source source,
496 enum mesa_debug_type type,
497 enum mesa_debug_severity severity,
498 GLboolean enabled)
499 {
500 int s, t, sev, smax, tmax, sevmax;
501 GLint gstack = ctx->Debug.GroupStackDepth;
502
503 if (source == MESA_DEBUG_SOURCE_COUNT) {
504 source = 0;
505 smax = MESA_DEBUG_SOURCE_COUNT;
506 } else {
507 smax = source+1;
508 }
509
510 if (type == MESA_DEBUG_TYPE_COUNT) {
511 type = 0;
512 tmax = MESA_DEBUG_TYPE_COUNT;
513 } else {
514 tmax = type+1;
515 }
516
517 if (severity == MESA_DEBUG_SEVERITY_COUNT) {
518 severity = 0;
519 sevmax = MESA_DEBUG_SEVERITY_COUNT;
520 } else {
521 sevmax = severity+1;
522 }
523
524 for (sev = severity; sev < sevmax; sev++)
525 for (s = source; s < smax; s++)
526 for (t = type; t < tmax; t++) {
527 struct simple_node *node;
528 struct gl_debug_severity *entry;
529
530 /* change the default for IDs we've never seen before. */
531 ctx->Debug.Defaults[gstack][sev][s][t] = enabled;
532
533 /* Now change the state of IDs we *have* seen... */
534 foreach(node, &ctx->Debug.Namespaces[gstack][s][t].Severity[sev]) {
535 entry = (struct gl_debug_severity *)node;
536 set_message_state(ctx, s, t, entry->ID, enabled);
537 }
538 }
539 }
540
541 /**
542 * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
543 * require special handling, since the IDs in them are controlled by clients,
544 * not the OpenGL implementation.
545 *
546 * 'count' is the length of the array 'ids'. If 'count' is nonzero, all
547 * the given IDs in the namespace defined by 'esource' and 'etype'
548 * will be affected.
549 *
550 * If 'count' is zero, this sets the state of all IDs that match
551 * the combination of 'esource', 'etype', and 'eseverity'.
552 */
553 static void
554 control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
555 GLenum eseverity, GLsizei count, const GLuint *ids,
556 GLboolean enabled)
557 {
558 GLsizei i;
559 enum mesa_debug_source source = gl_enum_to_debug_source(esource);
560 enum mesa_debug_type type = gl_enum_to_debug_type(etype);
561 enum mesa_debug_severity severity = gl_enum_to_debug_severity(eseverity);
562
563 for (i = 0; i < count; i++)
564 set_message_state(ctx, source, type, ids[i], enabled);
565
566 if (count)
567 return;
568
569 control_messages(ctx, source, type, severity, enabled);
570 }
571
572 /**
573 * This is a generic message control function for use by both
574 * glDebugMessageControlARB and glDebugMessageControl.
575 */
576 static void
577 message_control(GLenum gl_source, GLenum gl_type,
578 GLenum gl_severity,
579 GLsizei count, const GLuint *ids,
580 GLboolean enabled,
581 unsigned caller, const char *callerstr)
582 {
583 GET_CURRENT_CONTEXT(ctx);
584
585 if (count < 0) {
586 _mesa_error(ctx, GL_INVALID_VALUE,
587 "%s(count=%d : count must not be negative)", callerstr,
588 count);
589 return;
590 }
591
592 if (!validate_params(ctx, caller, callerstr, gl_source, gl_type,
593 gl_severity))
594 return; /* GL_INVALID_ENUM */
595
596 if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE
597 || gl_source == GL_DONT_CARE)) {
598 _mesa_error(ctx, GL_INVALID_OPERATION,
599 "%s(When passing an array of ids, severity must be"
600 " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.",
601 callerstr);
602 return;
603 }
604
605 control_app_messages(ctx, gl_source, gl_type, gl_severity,
606 count, ids, enabled);
607 }
608
609 /**
610 * This is a generic message insert function.
611 * Validation of source, type and severity parameters should be done
612 * before calling this funtion.
613 */
614 static void
615 message_insert(GLenum source, GLenum type, GLuint id,
616 GLenum severity, GLint length, const GLchar* buf,
617 const char *callerstr)
618 {
619 GET_CURRENT_CONTEXT(ctx);
620
621 if (length < 0)
622 length = strlen(buf);
623
624 if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
625 _mesa_error(ctx, GL_INVALID_VALUE,
626 "%s(length=%d, which is not less than "
627 "GL_MAX_DEBUG_MESSAGE_LENGTH=%d)", callerstr, length,
628 MAX_DEBUG_MESSAGE_LENGTH);
629 return;
630 }
631
632 _mesa_log_msg(ctx,
633 gl_enum_to_debug_source(source),
634 gl_enum_to_debug_type(type), id,
635 gl_enum_to_debug_severity(severity), length, buf);
636 }
637
638 /**
639 * This is a generic message insert function for use by both
640 * glGetDebugMessageLogARB and glGetDebugMessageLog.
641 */
642 static GLuint
643 get_message_log(GLuint count, GLsizei logSize, GLenum* sources,
644 GLenum* types, GLenum* ids, GLenum* severities,
645 GLsizei* lengths, GLchar* messageLog,
646 unsigned caller, const char *callerstr)
647 {
648 #define MESSAGE_LOG 1
649 #define MESSAGE_LOG_ARB 2
650 GET_CURRENT_CONTEXT(ctx);
651 GLuint ret;
652
653 if (!messageLog)
654 logSize = 0;
655
656 if (logSize < 0) {
657 _mesa_error(ctx, GL_INVALID_VALUE,
658 "%s(logSize=%d : logSize must not be negative)", callerstr,
659 logSize);
660 return 0;
661 }
662
663 for (ret = 0; ret < count; ret++) {
664 GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
665 logSize, messageLog);
666 if (!written)
667 break;
668
669 if (messageLog) {
670 messageLog += written;
671 logSize -= written;
672 }
673 if (lengths) {
674 *lengths = written;
675 lengths++;
676 }
677
678 if (severities)
679 severities++;
680 if (sources)
681 sources++;
682 if (types)
683 types++;
684 if (ids)
685 ids++;
686 }
687
688 return ret;
689 }
690
691 static void
692 do_nothing(GLuint key, void *data, void *userData)
693 {
694 }
695
696 static void
697 free_errors_data(struct gl_context *ctx, GLint gstack)
698 {
699 enum mesa_debug_type t;
700 enum mesa_debug_source s;
701 enum mesa_debug_severity sev;
702
703 /* Tear down state for filtering debug messages. */
704 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
705 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
706 _mesa_HashDeleteAll(ctx->Debug.Namespaces[gstack][s][t].IDs,
707 do_nothing, NULL);
708 _mesa_DeleteHashTable(ctx->Debug.Namespaces[gstack][s][t].IDs);
709 for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
710 struct simple_node *node, *tmp;
711 struct gl_debug_severity *entry;
712
713 foreach_s(node, tmp,
714 &ctx->Debug.Namespaces[gstack][s][t].Severity[sev]) {
715 entry = (struct gl_debug_severity *)node;
716 free(entry);
717 }
718 }
719 }
720 }
721
722 void GLAPIENTRY
723 _mesa_DebugMessageInsert(GLenum source, GLenum type, GLuint id,
724 GLenum severity, GLint length,
725 const GLchar* buf)
726 {
727 const char *callerstr = "glDebugMessageInsert";
728
729 GET_CURRENT_CONTEXT(ctx);
730
731 if (!validate_params(ctx, INSERT, callerstr, source, type, severity))
732 return; /* GL_INVALID_ENUM */
733
734 message_insert(source, type, id, severity, length, buf,
735 callerstr);
736 }
737
738 GLuint GLAPIENTRY
739 _mesa_GetDebugMessageLog(GLuint count, GLsizei logSize, GLenum* sources,
740 GLenum* types, GLenum* ids, GLenum* severities,
741 GLsizei* lengths, GLchar* messageLog)
742 {
743 const char *callerstr = "glGetDebugMessageLog";
744
745 return get_message_log(count, logSize, sources, types, ids, severities,
746 lengths, messageLog, MESSAGE_LOG, callerstr);
747 }
748
749 void GLAPIENTRY
750 _mesa_DebugMessageControl(GLenum source, GLenum type, GLenum severity,
751 GLsizei count, const GLuint *ids,
752 GLboolean enabled)
753 {
754 const char *callerstr = "glDebugMessageControl";
755
756 message_control(source, type, severity, count, ids,
757 enabled, CONTROL, callerstr);
758 }
759
760 void GLAPIENTRY
761 _mesa_DebugMessageCallback(GLDEBUGPROC callback, const void *userParam)
762 {
763 GET_CURRENT_CONTEXT(ctx);
764 ctx->Debug.Callback = callback;
765 ctx->Debug.CallbackData = userParam;
766 }
767
768 void GLAPIENTRY
769 _mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
770 const GLchar *message)
771 {
772 const char *callerstr = "glPushDebugGroup";
773 int s, t, sev;
774 GLint prevStackDepth;
775 GLint currStackDepth;
776 struct gl_debug_msg *emptySlot;
777
778 GET_CURRENT_CONTEXT(ctx);
779
780 if (ctx->Debug.GroupStackDepth >= MAX_DEBUG_GROUP_STACK_DEPTH-1) {
781 _mesa_error(ctx, GL_STACK_OVERFLOW, "%s", callerstr);
782 return;
783 }
784
785 switch(source) {
786 case GL_DEBUG_SOURCE_APPLICATION:
787 case GL_DEBUG_SOURCE_THIRD_PARTY:
788 break;
789 default:
790 _mesa_error(ctx, GL_INVALID_ENUM, "bad value passed to %s"
791 "(source=0x%x)", callerstr, source);
792 return;
793 }
794
795 message_insert(source, GL_DEBUG_TYPE_PUSH_GROUP, id,
796 GL_DEBUG_SEVERITY_NOTIFICATION, length,
797 message, callerstr);
798
799 prevStackDepth = ctx->Debug.GroupStackDepth;
800 ctx->Debug.GroupStackDepth++;
801 currStackDepth = ctx->Debug.GroupStackDepth;
802
803 /* pop reuses the message details from push so we store this */
804 if (length < 0)
805 length = strlen(message);
806 emptySlot = &ctx->Debug.DebugGroupMsgs[ctx->Debug.GroupStackDepth];
807 store_message_details(emptySlot, gl_enum_to_debug_source(source),
808 gl_enum_to_debug_source(GL_DEBUG_TYPE_PUSH_GROUP),
809 id,
810 gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
811 length, message);
812
813 /* inherit the control volume of the debug group previously residing on
814 * the top of the debug group stack
815 */
816 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
817 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
818 /* copy id settings */
819 ctx->Debug.Namespaces[currStackDepth][s][t].IDs =
820 _mesa_HashClone(ctx->Debug.Namespaces[prevStackDepth][s][t].IDs);
821
822 for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
823 struct gl_debug_severity *entry, *prevEntry;
824 struct simple_node *node;
825
826 /* copy default settings for unknown ids */
827 ctx->Debug.Defaults[currStackDepth][sev][s][t] = ctx->Debug.Defaults[prevStackDepth][sev][s][t];
828
829 /* copy known id severity settings */
830 make_empty_list(&ctx->Debug.Namespaces[currStackDepth][s][t].Severity[sev]);
831 foreach(node, &ctx->Debug.Namespaces[prevStackDepth][s][t].Severity[sev]) {
832 prevEntry = (struct gl_debug_severity *)node;
833 entry = malloc(sizeof *entry);
834 if (!entry)
835 return;
836
837 entry->ID = prevEntry->ID;
838 insert_at_tail(&ctx->Debug.Namespaces[currStackDepth][s][t].Severity[sev], &entry->link);
839 }
840 }
841 }
842 }
843
844 void GLAPIENTRY
845 _mesa_PopDebugGroup()
846 {
847 const char *callerstr = "glPopDebugGroup";
848 struct gl_debug_msg *gdmessage;
849 GLint prevStackDepth;
850
851 GET_CURRENT_CONTEXT(ctx);
852
853 if (ctx->Debug.GroupStackDepth <= 0) {
854 _mesa_error(ctx, GL_STACK_UNDERFLOW, "%s", callerstr);
855 return;
856 }
857
858 prevStackDepth = ctx->Debug.GroupStackDepth;
859 ctx->Debug.GroupStackDepth--;
860
861 gdmessage = &ctx->Debug.DebugGroupMsgs[prevStackDepth];
862 /* using _mesa_log_msg() directly here as verification of parameters
863 * already done in push
864 */
865 _mesa_log_msg(ctx, gdmessage->source,
866 gl_enum_to_debug_type(GL_DEBUG_TYPE_POP_GROUP),
867 gdmessage->id,
868 gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
869 gdmessage->length, gdmessage->message);
870
871 if (gdmessage->message != (char*)out_of_memory)
872 free(gdmessage->message);
873 gdmessage->message = NULL;
874 gdmessage->length = 0;
875
876 /* free popped debug group data */
877 free_errors_data(ctx, prevStackDepth);
878 }
879
880 void GLAPIENTRY
881 _mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
882 GLenum severity, GLint length,
883 const GLcharARB* buf)
884 {
885 const char *callerstr = "glDebugMessageInsertARB";
886
887 GET_CURRENT_CONTEXT(ctx);
888
889 if (!validate_params(ctx, INSERT_ARB, callerstr, source, type, severity))
890 return; /* GL_INVALID_ENUM */
891
892 message_insert(source, type, id, severity, length, buf,
893 callerstr);
894 }
895
896 GLuint GLAPIENTRY
897 _mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
898 GLenum* types, GLenum* ids, GLenum* severities,
899 GLsizei* lengths, GLcharARB* messageLog)
900 {
901 const char *callerstr = "glGetDebugMessageLogARB";
902
903 return get_message_log(count, logSize, sources, types, ids, severities,
904 lengths, messageLog, MESSAGE_LOG_ARB, callerstr);
905 }
906
907 void GLAPIENTRY
908 _mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type,
909 GLenum gl_severity,
910 GLsizei count, const GLuint *ids,
911 GLboolean enabled)
912 {
913 const char *callerstr = "glDebugMessageControlARB";
914
915 message_control(gl_source, gl_type, gl_severity, count, ids,
916 enabled, CONTROL_ARB, callerstr);
917 }
918
919 void GLAPIENTRY
920 _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const void *userParam)
921 {
922 GET_CURRENT_CONTEXT(ctx);
923 ctx->Debug.Callback = callback;
924 ctx->Debug.CallbackData = userParam;
925 }
926
927 void
928 _mesa_init_errors(struct gl_context *ctx)
929 {
930 int s, t, sev;
931
932 ctx->Debug.Callback = NULL;
933 ctx->Debug.SyncOutput = GL_FALSE;
934 ctx->Debug.Log[0].length = 0;
935 ctx->Debug.NumMessages = 0;
936 ctx->Debug.NextMsg = 0;
937 ctx->Debug.NextMsgLength = 0;
938 ctx->Debug.GroupStackDepth = 0;
939
940 /* Enable all the messages with severity HIGH or MEDIUM by default. */
941 memset(ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_HIGH], GL_TRUE,
942 sizeof ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_HIGH]);
943 memset(ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE,
944 sizeof ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_MEDIUM]);
945 memset(ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_LOW], GL_FALSE,
946 sizeof ctx->Debug.Defaults[0][MESA_DEBUG_SEVERITY_LOW]);
947
948 /* Initialize state for filtering known debug messages. */
949 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
950 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
951 ctx->Debug.Namespaces[0][s][t].IDs = _mesa_NewHashTable();
952 assert(ctx->Debug.Namespaces[0][s][t].IDs);
953
954 for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++)
955 make_empty_list(&ctx->Debug.Namespaces[0][s][t].Severity[sev]);
956 }
957 }
958
959 /**
960 * Loop through debug group stack tearing down states for
961 * filtering debug messages.
962 */
963 void
964 _mesa_free_errors_data(struct gl_context *ctx)
965 {
966 GLint i;
967
968 for (i = 0; i <= ctx->Debug.GroupStackDepth; i++) {
969 free_errors_data(ctx, i);
970 }
971 }
972
973 /**********************************************************************/
974 /** \name Diagnostics */
975 /*@{*/
976
977 static void
978 output_if_debug(const char *prefixString, const char *outputString,
979 GLboolean newline)
980 {
981 static int debug = -1;
982 static FILE *fout = NULL;
983
984 /* Init the local 'debug' var once.
985 * Note: the _mesa_init_debug() function should have been called
986 * by now so MESA_DEBUG_FLAGS will be initialized.
987 */
988 if (debug == -1) {
989 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
990 * etc to the named file. Otherwise, output to stderr.
991 */
992 const char *logFile = _mesa_getenv("MESA_LOG_FILE");
993 if (logFile)
994 fout = fopen(logFile, "w");
995 if (!fout)
996 fout = stderr;
997 #ifdef DEBUG
998 /* in debug builds, print messages unless MESA_DEBUG="silent" */
999 if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
1000 debug = 0;
1001 else
1002 debug = 1;
1003 #else
1004 /* in release builds, be silent unless MESA_DEBUG is set */
1005 debug = _mesa_getenv("MESA_DEBUG") != NULL;
1006 #endif
1007 }
1008
1009 /* Now only print the string if we're required to do so. */
1010 if (debug) {
1011 fprintf(fout, "%s: %s", prefixString, outputString);
1012 if (newline)
1013 fprintf(fout, "\n");
1014 fflush(fout);
1015
1016 #if defined(_WIN32) && !defined(_WIN32_WCE)
1017 /* stderr from windows applications without console is not usually
1018 * visible, so communicate with the debugger instead */
1019 {
1020 char buf[4096];
1021 _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
1022 OutputDebugStringA(buf);
1023 }
1024 #endif
1025 }
1026 }
1027
1028 /**
1029 * When a new type of error is recorded, print a message describing
1030 * previous errors which were accumulated.
1031 */
1032 static void
1033 flush_delayed_errors( struct gl_context *ctx )
1034 {
1035 char s[MAX_DEBUG_MESSAGE_LENGTH];
1036
1037 if (ctx->ErrorDebugCount) {
1038 _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
1039 ctx->ErrorDebugCount,
1040 _mesa_lookup_enum_by_nr(ctx->ErrorValue));
1041
1042 output_if_debug("Mesa", s, GL_TRUE);
1043
1044 ctx->ErrorDebugCount = 0;
1045 }
1046 }
1047
1048
1049 /**
1050 * Report a warning (a recoverable error condition) to stderr if
1051 * either DEBUG is defined or the MESA_DEBUG env var is set.
1052 *
1053 * \param ctx GL context.
1054 * \param fmtString printf()-like format string.
1055 */
1056 void
1057 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
1058 {
1059 char str[MAX_DEBUG_MESSAGE_LENGTH];
1060 va_list args;
1061 va_start( args, fmtString );
1062 (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
1063 va_end( args );
1064
1065 if (ctx)
1066 flush_delayed_errors( ctx );
1067
1068 output_if_debug("Mesa warning", str, GL_TRUE);
1069 }
1070
1071
1072 /**
1073 * Report an internal implementation problem.
1074 * Prints the message to stderr via fprintf().
1075 *
1076 * \param ctx GL context.
1077 * \param fmtString problem description string.
1078 */
1079 void
1080 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
1081 {
1082 va_list args;
1083 char str[MAX_DEBUG_MESSAGE_LENGTH];
1084 static int numCalls = 0;
1085
1086 (void) ctx;
1087
1088 if (numCalls < 50) {
1089 numCalls++;
1090
1091 va_start( args, fmtString );
1092 _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
1093 va_end( args );
1094 fprintf(stderr, "Mesa %s implementation error: %s\n",
1095 PACKAGE_VERSION, str);
1096 fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
1097 }
1098 }
1099
1100 static GLboolean
1101 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
1102 {
1103 static GLint debug = -1;
1104
1105 /* Check debug environment variable only once:
1106 */
1107 if (debug == -1) {
1108 const char *debugEnv = _mesa_getenv("MESA_DEBUG");
1109
1110 #ifdef DEBUG
1111 if (debugEnv && strstr(debugEnv, "silent"))
1112 debug = GL_FALSE;
1113 else
1114 debug = GL_TRUE;
1115 #else
1116 if (debugEnv)
1117 debug = GL_TRUE;
1118 else
1119 debug = GL_FALSE;
1120 #endif
1121 }
1122
1123 if (debug) {
1124 if (ctx->ErrorValue != error ||
1125 ctx->ErrorDebugFmtString != fmtString) {
1126 flush_delayed_errors( ctx );
1127 ctx->ErrorDebugFmtString = fmtString;
1128 ctx->ErrorDebugCount = 0;
1129 return GL_TRUE;
1130 }
1131 ctx->ErrorDebugCount++;
1132 }
1133 return GL_FALSE;
1134 }
1135
1136 void
1137 _mesa_gl_debug(struct gl_context *ctx,
1138 GLuint *id,
1139 enum mesa_debug_type type,
1140 enum mesa_debug_severity severity,
1141 const char *fmtString, ...)
1142 {
1143 char s[MAX_DEBUG_MESSAGE_LENGTH];
1144 int len;
1145 va_list args;
1146
1147 debug_get_id(id);
1148
1149 va_start(args, fmtString);
1150 len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
1151 va_end(args);
1152
1153 _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, type,
1154 *id, severity, len, s);
1155 }
1156
1157
1158 /**
1159 * Record an OpenGL state error. These usually occur when the user
1160 * passes invalid parameters to a GL function.
1161 *
1162 * If debugging is enabled (either at compile-time via the DEBUG macro, or
1163 * run-time via the MESA_DEBUG environment variable), report the error with
1164 * _mesa_debug().
1165 *
1166 * \param ctx the GL context.
1167 * \param error the error value.
1168 * \param fmtString printf() style format string, followed by optional args
1169 */
1170 void
1171 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
1172 {
1173 GLboolean do_output, do_log;
1174 /* Ideally this would be set up by the caller, so that we had proper IDs
1175 * per different message.
1176 */
1177 static GLuint error_msg_id = 0;
1178
1179 debug_get_id(&error_msg_id);
1180
1181 do_output = should_output(ctx, error, fmtString);
1182 do_log = should_log(ctx,
1183 MESA_DEBUG_SOURCE_API,
1184 MESA_DEBUG_TYPE_ERROR,
1185 error_msg_id,
1186 MESA_DEBUG_SEVERITY_HIGH);
1187
1188 if (do_output || do_log) {
1189 char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
1190 int len;
1191 va_list args;
1192
1193 va_start(args, fmtString);
1194 len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
1195 va_end(args);
1196
1197 if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
1198 /* Too long error message. Whoever calls _mesa_error should use
1199 * shorter strings. */
1200 ASSERT(0);
1201 return;
1202 }
1203
1204 len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
1205 _mesa_lookup_enum_by_nr(error), s);
1206 if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
1207 /* Same as above. */
1208 ASSERT(0);
1209 return;
1210 }
1211
1212 /* Print the error to stderr if needed. */
1213 if (do_output) {
1214 output_if_debug("Mesa: User error", s2, GL_TRUE);
1215 }
1216
1217 /* Log the error via ARB_debug_output if needed.*/
1218 if (do_log) {
1219 _mesa_log_msg(ctx,
1220 MESA_DEBUG_SOURCE_API,
1221 MESA_DEBUG_TYPE_ERROR,
1222 error_msg_id,
1223 MESA_DEBUG_SEVERITY_HIGH, len, s2);
1224 }
1225 }
1226
1227 /* Set the GL context error state for glGetError. */
1228 _mesa_record_error(ctx, error);
1229 }
1230
1231
1232 /**
1233 * Report debug information. Print error message to stderr via fprintf().
1234 * No-op if DEBUG mode not enabled.
1235 *
1236 * \param ctx GL context.
1237 * \param fmtString printf()-style format string, followed by optional args.
1238 */
1239 void
1240 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
1241 {
1242 #ifdef DEBUG
1243 char s[MAX_DEBUG_MESSAGE_LENGTH];
1244 va_list args;
1245 va_start(args, fmtString);
1246 _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
1247 va_end(args);
1248 output_if_debug("Mesa", s, GL_FALSE);
1249 #endif /* DEBUG */
1250 (void) ctx;
1251 (void) fmtString;
1252 }
1253
1254
1255 /**
1256 * Report debug information from the shader compiler via GL_ARB_debug_output.
1257 *
1258 * \param ctx GL context.
1259 * \param type The namespace to which this message belongs.
1260 * \param id The message ID within the given namespace.
1261 * \param msg The message to output. Need not be null-terminated.
1262 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
1263 */
1264 void
1265 _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint *id,
1266 const char *msg, int len )
1267 {
1268 enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
1269 enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
1270
1271 debug_get_id(id);
1272
1273 if (len < 0)
1274 len = strlen(msg);
1275
1276 /* Truncate the message if necessary. */
1277 if (len >= MAX_DEBUG_MESSAGE_LENGTH)
1278 len = MAX_DEBUG_MESSAGE_LENGTH - 1;
1279
1280 _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
1281 }
1282
1283 /*@}*/