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