r600g: pad the DMA CS to a multiple of 8 dwords
[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
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
40
41 #define MAXSTRING MAX_DEBUG_MESSAGE_LENGTH
42
43
44 struct gl_client_severity
45 {
46 struct simple_node link;
47 GLuint ID;
48 };
49
50 static char out_of_memory[] = "Debugging error: out of memory";
51
52 #define enum_is(e, kind1, kind2) \
53 ((e) == GL_DEBUG_##kind1##_##kind2##_ARB || (e) == GL_DONT_CARE)
54 #define severity_is(sev, kind) enum_is(sev, SEVERITY, kind)
55 #define source_is(s, kind) enum_is(s, SOURCE, kind)
56 #define type_is(t, kind) enum_is(t, TYPE, kind)
57
58 /* Prevent define collision on Windows */
59 #undef ERROR
60
61 enum {
62 SOURCE_APPLICATION,
63 SOURCE_THIRD_PARTY,
64
65 SOURCE_COUNT,
66 SOURCE_ANY = -1
67 };
68
69 enum {
70 TYPE_ERROR,
71 TYPE_DEPRECATED,
72 TYPE_UNDEFINED,
73 TYPE_PORTABILITY,
74 TYPE_PERFORMANCE,
75 TYPE_OTHER,
76
77 TYPE_COUNT,
78 TYPE_ANY = -1
79 };
80
81 enum {
82 SEVERITY_LOW,
83 SEVERITY_MEDIUM,
84 SEVERITY_HIGH,
85
86 SEVERITY_COUNT,
87 SEVERITY_ANY = -1
88 };
89
90 static int
91 enum_to_index(GLenum e)
92 {
93 switch (e) {
94 case GL_DEBUG_SOURCE_APPLICATION_ARB:
95 return (int)SOURCE_APPLICATION;
96 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
97 return (int)SOURCE_THIRD_PARTY;
98
99 case GL_DEBUG_TYPE_ERROR_ARB:
100 return (int)TYPE_ERROR;
101 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
102 return (int)TYPE_DEPRECATED;
103 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
104 return (int)TYPE_UNDEFINED;
105 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
106 return (int)TYPE_PERFORMANCE;
107 case GL_DEBUG_TYPE_PORTABILITY_ARB:
108 return (int)TYPE_PORTABILITY;
109 case GL_DEBUG_TYPE_OTHER_ARB:
110 return (int)TYPE_OTHER;
111
112 case GL_DEBUG_SEVERITY_LOW_ARB:
113 return (int)SEVERITY_LOW;
114 case GL_DEBUG_SEVERITY_MEDIUM_ARB:
115 return (int)SEVERITY_MEDIUM;
116 case GL_DEBUG_SEVERITY_HIGH_ARB:
117 return (int)SEVERITY_HIGH;
118
119 case GL_DONT_CARE:
120 return (int)TYPE_ANY;
121
122 default:
123 assert(0 && "unreachable");
124 return -2;
125 };
126 }
127
128
129 /*
130 * We store a bitfield in the hash table, with five possible values total.
131 *
132 * The ENABLED_BIT's purpose is self-explanatory.
133 *
134 * The FOUND_BIT is needed to differentiate the value of DISABLED from
135 * the value returned by HashTableLookup() when it can't find the given key.
136 *
137 * The KNOWN_SEVERITY bit is a bit complicated:
138 *
139 * A client may call Control() with an array of IDs, then call Control()
140 * on all message IDs of a certain severity, then Insert() one of the
141 * previously specified IDs, giving us a known severity level, then call
142 * Control() on all message IDs of a certain severity level again.
143 *
144 * After the first call, those IDs will have a FOUND_BIT, but will not
145 * exist in any severity-specific list, so the second call will not
146 * impact them. This is undesirable but unavoidable given the API:
147 * The only entrypoint that gives a severity for a client-defined ID
148 * is the Insert() call.
149 *
150 * For the sake of Control(), we want to maintain the invariant
151 * that an ID will either appear in none of the three severity lists,
152 * or appear once, to minimize pointless duplication and potential surprises.
153 *
154 * Because Insert() is the only place that will learn an ID's severity,
155 * it should insert an ID into the appropriate list, but only if the ID
156 * doesn't exist in it or any other list yet. Because searching all three
157 * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
158 */
159 enum {
160 FOUND_BIT = 1 << 0,
161 ENABLED_BIT = 1 << 1,
162 KNOWN_SEVERITY = 1 << 2,
163
164 /* HashTable reserves zero as a return value meaning 'not found' */
165 NOT_FOUND = 0,
166 DISABLED = FOUND_BIT,
167 ENABLED = ENABLED_BIT | FOUND_BIT
168 };
169
170 /**
171 * Returns the state of the given message ID in a client-controlled
172 * namespace.
173 * 'source', 'type', and 'severity' are array indices like TYPE_ERROR,
174 * not GL enums.
175 */
176 static GLboolean
177 get_message_state(struct gl_context *ctx, int source, int type,
178 GLuint id, int severity)
179 {
180 struct gl_client_namespace *nspace =
181 &ctx->Debug.ClientIDs.Namespaces[source][type];
182 uintptr_t state;
183
184 /* In addition to not being able to store zero as a value, HashTable also
185 can't use zero as a key. */
186 if (id)
187 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
188 else
189 state = nspace->ZeroID;
190
191 /* Only do this once for each ID. This makes sure the ID exists in,
192 at most, one list, and does not pointlessly appear multiple times. */
193 if (!(state & KNOWN_SEVERITY)) {
194 struct gl_client_severity *entry;
195
196 if (state == NOT_FOUND) {
197 if (ctx->Debug.ClientIDs.Defaults[severity][source][type])
198 state = ENABLED;
199 else
200 state = DISABLED;
201 }
202
203 entry = malloc(sizeof *entry);
204 if (!entry)
205 goto out;
206
207 state |= KNOWN_SEVERITY;
208
209 if (id)
210 _mesa_HashInsert(nspace->IDs, id, (void*)state);
211 else
212 nspace->ZeroID = state;
213
214 entry->ID = id;
215 insert_at_tail(&nspace->Severity[severity], &entry->link);
216 }
217
218 out:
219 return !!(state & ENABLED_BIT);
220 }
221
222 /**
223 * Sets the state of the given message ID in a client-controlled
224 * namespace.
225 * 'source' and 'type' are array indices like TYPE_ERROR, not GL enums.
226 */
227 static void
228 set_message_state(struct gl_context *ctx, int source, int type,
229 GLuint id, GLboolean enabled)
230 {
231 struct gl_client_namespace *nspace =
232 &ctx->Debug.ClientIDs.Namespaces[source][type];
233 uintptr_t state;
234
235 /* In addition to not being able to store zero as a value, HashTable also
236 can't use zero as a key. */
237 if (id)
238 state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
239 else
240 state = nspace->ZeroID;
241
242 if (state == NOT_FOUND)
243 state = enabled ? ENABLED : DISABLED;
244 else {
245 if (enabled)
246 state |= ENABLED_BIT;
247 else
248 state &= ~ENABLED_BIT;
249 }
250
251 if (id)
252 _mesa_HashInsert(nspace->IDs, id, (void*)state);
253 else
254 nspace->ZeroID = state;
255 }
256
257 /**
258 * Whether a debugging message should be logged or not.
259 * For implementation-controlled namespaces, we keep an array
260 * of booleans per namespace, per context, recording whether
261 * each individual message is enabled or not. The message ID
262 * is an index into the namespace's array.
263 */
264 static GLboolean
265 should_log(struct gl_context *ctx, GLenum source, GLenum type,
266 GLuint id, GLenum severity)
267 {
268 if (source == GL_DEBUG_SOURCE_APPLICATION_ARB ||
269 source == GL_DEBUG_SOURCE_THIRD_PARTY_ARB) {
270 int s, t, sev;
271 s = enum_to_index(source);
272 t = enum_to_index(type);
273 sev = enum_to_index(severity);
274
275 return get_message_state(ctx, s, t, sev, id);
276 }
277
278 if (type_is(type, ERROR)) {
279 if (source_is(source, API))
280 return ctx->Debug.ApiErrors[id];
281 if (source_is(source, WINDOW_SYSTEM))
282 return ctx->Debug.WinsysErrors[id];
283 if (source_is(source, SHADER_COMPILER))
284 return ctx->Debug.ShaderErrors[id];
285 if (source_is(source, OTHER))
286 return ctx->Debug.OtherErrors[id];
287 }
288
289 return (severity != GL_DEBUG_SEVERITY_LOW_ARB);
290 }
291
292 /**
293 * 'buf' is not necessarily a null-terminated string. When logging, copy
294 * 'len' characters from it, store them in a new, null-terminated string,
295 * and remember the number of bytes used by that string, *including*
296 * the null terminator this time.
297 */
298 static void
299 _mesa_log_msg(struct gl_context *ctx, GLenum source, GLenum type,
300 GLuint id, GLenum severity, GLint len, const char *buf)
301 {
302 GLint nextEmpty;
303 struct gl_debug_msg *emptySlot;
304
305 assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH);
306
307 if (!should_log(ctx, source, type, id, severity))
308 return;
309
310 if (ctx->Debug.Callback) {
311 ctx->Debug.Callback(source, type, id, severity,
312 len, buf, ctx->Debug.CallbackData);
313 return;
314 }
315
316 if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
317 return;
318
319 nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages)
320 % MAX_DEBUG_LOGGED_MESSAGES;
321 emptySlot = &ctx->Debug.Log[nextEmpty];
322
323 assert(!emptySlot->message && !emptySlot->length);
324
325 emptySlot->message = malloc(len+1);
326 if (emptySlot->message) {
327 (void) strncpy(emptySlot->message, buf, (size_t)len);
328 emptySlot->message[len] = '\0';
329
330 emptySlot->length = len+1;
331 emptySlot->source = source;
332 emptySlot->type = type;
333 emptySlot->id = id;
334 emptySlot->severity = severity;
335 } else {
336 /* malloc failed! */
337 emptySlot->message = out_of_memory;
338 emptySlot->length = strlen(out_of_memory)+1;
339 emptySlot->source = GL_DEBUG_SOURCE_OTHER_ARB;
340 emptySlot->type = GL_DEBUG_TYPE_ERROR_ARB;
341 emptySlot->id = OTHER_ERROR_OUT_OF_MEMORY;
342 emptySlot->severity = GL_DEBUG_SEVERITY_HIGH_ARB;
343 }
344
345 if (ctx->Debug.NumMessages == 0)
346 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
347
348 ctx->Debug.NumMessages++;
349 }
350
351 /**
352 * Pop the oldest debug message out of the log.
353 * Writes the message string, including the null terminator, into 'buf',
354 * using up to 'bufSize' bytes. If 'bufSize' is too small, or
355 * if 'buf' is NULL, nothing is written.
356 *
357 * Returns the number of bytes written on success, or when 'buf' is NULL,
358 * the number that would have been written. A return value of 0
359 * indicates failure.
360 */
361 static GLsizei
362 _mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
363 GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
364 {
365 struct gl_debug_msg *msg;
366 GLsizei length;
367
368 if (ctx->Debug.NumMessages == 0)
369 return 0;
370
371 msg = &ctx->Debug.Log[ctx->Debug.NextMsg];
372 length = msg->length;
373
374 assert(length > 0 && length == ctx->Debug.NextMsgLength);
375
376 if (bufSize < length && buf != NULL)
377 return 0;
378
379 if (severity)
380 *severity = msg->severity;
381 if (source)
382 *source = msg->source;
383 if (type)
384 *type = msg->type;
385 if (id)
386 *id = msg->id;
387
388 if (buf) {
389 assert(msg->message[length-1] == '\0');
390 (void) strncpy(buf, msg->message, (size_t)length);
391 }
392
393 if (msg->message != (char*)out_of_memory)
394 free(msg->message);
395 msg->message = NULL;
396 msg->length = 0;
397
398 ctx->Debug.NumMessages--;
399 ctx->Debug.NextMsg++;
400 ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
401 ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
402
403 return length;
404 }
405
406 /**
407 * Verify that source, type, and severity are valid enums.
408 * glDebugMessageInsertARB only accepts two values for 'source',
409 * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
410 * in any parameter, so handle those cases specially.
411 */
412 static GLboolean
413 validate_params(struct gl_context *ctx, unsigned caller,
414 GLenum source, GLenum type, GLenum severity)
415 {
416 #define INSERT 1
417 #define CONTROL 2
418 switch(source) {
419 case GL_DEBUG_SOURCE_APPLICATION_ARB:
420 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
421 break;
422 case GL_DEBUG_SOURCE_API_ARB:
423 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
424 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
425 case GL_DEBUG_SOURCE_OTHER_ARB:
426 if (caller != INSERT)
427 break;
428 case GL_DONT_CARE:
429 if (caller == CONTROL)
430 break;
431 default:
432 goto error;
433 }
434
435 switch(type) {
436 case GL_DEBUG_TYPE_ERROR_ARB:
437 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
438 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
439 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
440 case GL_DEBUG_TYPE_PORTABILITY_ARB:
441 case GL_DEBUG_TYPE_OTHER_ARB:
442 break;
443 case GL_DONT_CARE:
444 if (caller == CONTROL)
445 break;
446 default:
447 goto error;
448 }
449
450 switch(severity) {
451 case GL_DEBUG_SEVERITY_HIGH_ARB:
452 case GL_DEBUG_SEVERITY_MEDIUM_ARB:
453 case GL_DEBUG_SEVERITY_LOW_ARB:
454 break;
455 case GL_DONT_CARE:
456 if (caller == CONTROL)
457 break;
458 default:
459 goto error;
460 }
461 return GL_TRUE;
462
463 error:
464 {
465 const char *callerstr;
466 if (caller == INSERT)
467 callerstr = "glDebugMessageInsertARB";
468 else if (caller == CONTROL)
469 callerstr = "glDebugMessageControlARB";
470 else
471 return GL_FALSE;
472
473 _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s"
474 "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
475 source, type, severity);
476 }
477 return GL_FALSE;
478 }
479
480 void GLAPIENTRY
481 _mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
482 GLenum severity, GLint length,
483 const GLcharARB* buf)
484 {
485 GET_CURRENT_CONTEXT(ctx);
486
487 if (!validate_params(ctx, INSERT, source, type, severity))
488 return; /* GL_INVALID_ENUM */
489
490 if (length < 0)
491 length = strlen(buf);
492
493 if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
494 _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB"
495 "(length=%d, which is not less than "
496 "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length,
497 MAX_DEBUG_MESSAGE_LENGTH);
498 return;
499 }
500
501 _mesa_log_msg(ctx, source, type, id, severity, length, buf);
502 }
503
504 GLuint GLAPIENTRY
505 _mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
506 GLenum* types, GLenum* ids, GLenum* severities,
507 GLsizei* lengths, GLcharARB* messageLog)
508 {
509 GET_CURRENT_CONTEXT(ctx);
510 GLuint ret;
511
512 if (!messageLog)
513 logSize = 0;
514
515 if (logSize < 0) {
516 _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB"
517 "(logSize=%d : logSize must not be negative)", logSize);
518 return 0;
519 }
520
521 for (ret = 0; ret < count; ret++) {
522 GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
523 logSize, messageLog);
524 if (!written)
525 break;
526
527 if (messageLog) {
528 messageLog += written;
529 logSize -= written;
530 }
531 if (lengths) {
532 *lengths = written;
533 lengths++;
534 }
535
536 if (severities)
537 severities++;
538 if (sources)
539 sources++;
540 if (types)
541 types++;
542 if (ids)
543 ids++;
544 }
545
546 return ret;
547 }
548
549 /**
550 * 'array' is an array representing a particular debugging-message namespace.
551 * I.e., the set of all API errors, or the set of all Shader Compiler errors.
552 * 'size' is the size of 'array'. 'count' is the size of 'ids', an array
553 * of indices into 'array'. All the elements of 'array' at the indices
554 * listed in 'ids' will be overwritten with the value of 'enabled'.
555 *
556 * If 'count' is zero, all elements in 'array' are overwritten with the
557 * value of 'enabled'.
558 */
559 static void
560 control_messages(GLboolean *array, GLuint size,
561 GLsizei count, const GLuint *ids, GLboolean enabled)
562 {
563 GLsizei i;
564
565 if (!count) {
566 GLuint id;
567 for (id = 0; id < size; id++) {
568 array[id] = enabled;
569 }
570 return;
571 }
572
573 for (i = 0; i < count; i++) {
574 if (ids[i] >= size) {
575 /* XXX: The spec doesn't say what to do with a non-existent ID. */
576 continue;
577 }
578 array[ids[i]] = enabled;
579 }
580 }
581
582 /**
583 * Set the state of all message IDs found in the given intersection
584 * of 'source', 'type', and 'severity'. Note that all three of these
585 * parameters are array indices, not the corresponding GL enums.
586 *
587 * This requires both setting the state of all previously seen message
588 * IDs in the hash table, and setting the default state for all
589 * applicable combinations of source/type/severity, so that all the
590 * yet-unknown message IDs that may be used in the future will be
591 * impacted as if they were already known.
592 */
593 static void
594 control_app_messages_by_group(struct gl_context *ctx, int source, int type,
595 int severity, GLboolean enabled)
596 {
597 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
598 int s, t, sev, smax, tmax, sevmax;
599
600 if (source == SOURCE_ANY) {
601 source = 0;
602 smax = SOURCE_COUNT;
603 } else {
604 smax = source+1;
605 }
606
607 if (type == TYPE_ANY) {
608 type = 0;
609 tmax = TYPE_COUNT;
610 } else {
611 tmax = type+1;
612 }
613
614 if (severity == SEVERITY_ANY) {
615 severity = 0;
616 sevmax = SEVERITY_COUNT;
617 } else {
618 sevmax = severity+1;
619 }
620
621 for (sev = severity; sev < sevmax; sev++)
622 for (s = source; s < smax; s++)
623 for (t = type; t < tmax; t++) {
624 struct simple_node *node;
625 struct gl_client_severity *entry;
626
627 /* change the default for IDs we've never seen before. */
628 ClientIDs->Defaults[sev][s][t] = enabled;
629
630 /* Now change the state of IDs we *have* seen... */
631 foreach(node, &ClientIDs->Namespaces[s][t].Severity[sev]) {
632 entry = (struct gl_client_severity *)node;
633 set_message_state(ctx, s, t, entry->ID, enabled);
634 }
635 }
636 }
637
638 /**
639 * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
640 * require special handling, since the IDs in them are controlled by clients,
641 * not the OpenGL implementation.
642 *
643 * 'count' is the length of the array 'ids'. If 'count' is nonzero, all
644 * the given IDs in the namespace defined by 'esource' and 'etype'
645 * will be affected.
646 *
647 * If 'count' is zero, this sets the state of all IDs that match
648 * the combination of 'esource', 'etype', and 'eseverity'.
649 */
650 static void
651 control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
652 GLenum eseverity, GLsizei count, const GLuint *ids,
653 GLboolean enabled)
654 {
655 int source, type, severity;
656 GLsizei i;
657
658 source = enum_to_index(esource);
659 type = enum_to_index(etype);
660 severity = enum_to_index(eseverity);
661
662 if (count)
663 assert(severity == SEVERITY_ANY && type != TYPE_ANY
664 && source != SOURCE_ANY);
665
666 for (i = 0; i < count; i++)
667 set_message_state(ctx, source, type, ids[i], enabled);
668
669 if (count)
670 return;
671
672 control_app_messages_by_group(ctx, source, type, severity, enabled);
673 }
674
675 void GLAPIENTRY
676 _mesa_DebugMessageControlARB(GLenum source, GLenum type, GLenum severity,
677 GLsizei count, const GLuint *ids,
678 GLboolean enabled)
679 {
680 GET_CURRENT_CONTEXT(ctx);
681
682 if (count < 0) {
683 _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageControlARB"
684 "(count=%d : count must not be negative)", count);
685 return;
686 }
687
688 if (!validate_params(ctx, CONTROL, source, type, severity))
689 return; /* GL_INVALID_ENUM */
690
691 if (count && (severity != GL_DONT_CARE || type == GL_DONT_CARE
692 || source == GL_DONT_CARE)) {
693 _mesa_error(ctx, GL_INVALID_OPERATION, "glDebugMessageControlARB"
694 "(When passing an array of ids, severity must be"
695 " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.");
696 return;
697 }
698
699 if (source_is(source, APPLICATION) || source_is(source, THIRD_PARTY))
700 control_app_messages(ctx, source, type, severity, count, ids, enabled);
701
702 if (severity_is(severity, HIGH)) {
703 if (type_is(type, ERROR)) {
704 if (source_is(source, API))
705 control_messages(ctx->Debug.ApiErrors, API_ERROR_COUNT,
706 count, ids, enabled);
707 if (source_is(source, WINDOW_SYSTEM))
708 control_messages(ctx->Debug.WinsysErrors, WINSYS_ERROR_COUNT,
709 count, ids, enabled);
710 if (source_is(source, SHADER_COMPILER))
711 control_messages(ctx->Debug.ShaderErrors, SHADER_ERROR_COUNT,
712 count, ids, enabled);
713 if (source_is(source, OTHER))
714 control_messages(ctx->Debug.OtherErrors, OTHER_ERROR_COUNT,
715 count, ids, enabled);
716 }
717 }
718 }
719
720 void GLAPIENTRY
721 _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const GLvoid *userParam)
722 {
723 GET_CURRENT_CONTEXT(ctx);
724 ctx->Debug.Callback = callback;
725 ctx->Debug.CallbackData = (void *) userParam;
726 }
727
728 void
729 _mesa_init_errors(struct gl_context *ctx)
730 {
731 int s, t, sev;
732 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
733
734 ctx->Debug.Callback = NULL;
735 ctx->Debug.SyncOutput = GL_FALSE;
736 ctx->Debug.Log[0].length = 0;
737 ctx->Debug.NumMessages = 0;
738 ctx->Debug.NextMsg = 0;
739 ctx->Debug.NextMsgLength = 0;
740
741 /* Enable all the messages with severity HIGH or MEDIUM by default. */
742 memset(ctx->Debug.ApiErrors, GL_TRUE, sizeof ctx->Debug.ApiErrors);
743 memset(ctx->Debug.WinsysErrors, GL_TRUE, sizeof ctx->Debug.WinsysErrors);
744 memset(ctx->Debug.ShaderErrors, GL_TRUE, sizeof ctx->Debug.ShaderErrors);
745 memset(ctx->Debug.OtherErrors, GL_TRUE, sizeof ctx->Debug.OtherErrors);
746 memset(ClientIDs->Defaults[SEVERITY_HIGH], GL_TRUE,
747 sizeof ClientIDs->Defaults[SEVERITY_HIGH]);
748 memset(ClientIDs->Defaults[SEVERITY_MEDIUM], GL_TRUE,
749 sizeof ClientIDs->Defaults[SEVERITY_MEDIUM]);
750 memset(ClientIDs->Defaults[SEVERITY_LOW], GL_FALSE,
751 sizeof ClientIDs->Defaults[SEVERITY_LOW]);
752
753 /* Initialize state for filtering client-provided debug messages. */
754 for (s = 0; s < SOURCE_COUNT; s++)
755 for (t = 0; t < TYPE_COUNT; t++) {
756 ClientIDs->Namespaces[s][t].IDs = _mesa_NewHashTable();
757 assert(ClientIDs->Namespaces[s][t].IDs);
758
759 for (sev = 0; sev < SEVERITY_COUNT; sev++)
760 make_empty_list(&ClientIDs->Namespaces[s][t].Severity[sev]);
761 }
762 }
763
764 void
765 _mesa_free_errors_data(struct gl_context *ctx)
766 {
767 int s, t, sev;
768 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
769
770 /* Tear down state for filtering client-provided debug messages. */
771 for (s = 0; s < SOURCE_COUNT; s++)
772 for (t = 0; t < TYPE_COUNT; t++) {
773 _mesa_DeleteHashTable(ClientIDs->Namespaces[s][t].IDs);
774 for (sev = 0; sev < SEVERITY_COUNT; sev++) {
775 struct simple_node *node, *tmp;
776 struct gl_client_severity *entry;
777
778 foreach_s(node, tmp, &ClientIDs->Namespaces[s][t].Severity[sev]) {
779 entry = (struct gl_client_severity *)node;
780 free(entry);
781 }
782 }
783 }
784 }
785
786 /**********************************************************************/
787 /** \name Diagnostics */
788 /*@{*/
789
790 static void
791 output_if_debug(const char *prefixString, const char *outputString,
792 GLboolean newline)
793 {
794 static int debug = -1;
795 static FILE *fout = NULL;
796
797 /* Init the local 'debug' var once.
798 * Note: the _mesa_init_debug() function should have been called
799 * by now so MESA_DEBUG_FLAGS will be initialized.
800 */
801 if (debug == -1) {
802 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
803 * etc to the named file. Otherwise, output to stderr.
804 */
805 const char *logFile = _mesa_getenv("MESA_LOG_FILE");
806 if (logFile)
807 fout = fopen(logFile, "w");
808 if (!fout)
809 fout = stderr;
810 #ifdef DEBUG
811 /* in debug builds, print messages unless MESA_DEBUG="silent" */
812 if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
813 debug = 0;
814 else
815 debug = 1;
816 #else
817 /* in release builds, be silent unless MESA_DEBUG is set */
818 debug = _mesa_getenv("MESA_DEBUG") != NULL;
819 #endif
820 }
821
822 /* Now only print the string if we're required to do so. */
823 if (debug) {
824 fprintf(fout, "%s: %s", prefixString, outputString);
825 if (newline)
826 fprintf(fout, "\n");
827 fflush(fout);
828
829 #if defined(_WIN32) && !defined(_WIN32_WCE)
830 /* stderr from windows applications without console is not usually
831 * visible, so communicate with the debugger instead */
832 {
833 char buf[4096];
834 _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
835 OutputDebugStringA(buf);
836 }
837 #endif
838 }
839 }
840
841
842 /**
843 * Return string version of GL error code.
844 */
845 static const char *
846 error_string( GLenum error )
847 {
848 switch (error) {
849 case GL_NO_ERROR:
850 return "GL_NO_ERROR";
851 case GL_INVALID_VALUE:
852 return "GL_INVALID_VALUE";
853 case GL_INVALID_ENUM:
854 return "GL_INVALID_ENUM";
855 case GL_INVALID_OPERATION:
856 return "GL_INVALID_OPERATION";
857 case GL_STACK_OVERFLOW:
858 return "GL_STACK_OVERFLOW";
859 case GL_STACK_UNDERFLOW:
860 return "GL_STACK_UNDERFLOW";
861 case GL_OUT_OF_MEMORY:
862 return "GL_OUT_OF_MEMORY";
863 case GL_TABLE_TOO_LARGE:
864 return "GL_TABLE_TOO_LARGE";
865 case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
866 return "GL_INVALID_FRAMEBUFFER_OPERATION";
867 default:
868 return "unknown";
869 }
870 }
871
872
873 /**
874 * When a new type of error is recorded, print a message describing
875 * previous errors which were accumulated.
876 */
877 static void
878 flush_delayed_errors( struct gl_context *ctx )
879 {
880 char s[MAXSTRING];
881
882 if (ctx->ErrorDebugCount) {
883 _mesa_snprintf(s, MAXSTRING, "%d similar %s errors",
884 ctx->ErrorDebugCount,
885 error_string(ctx->ErrorValue));
886
887 output_if_debug("Mesa", s, GL_TRUE);
888
889 ctx->ErrorDebugCount = 0;
890 }
891 }
892
893
894 /**
895 * Report a warning (a recoverable error condition) to stderr if
896 * either DEBUG is defined or the MESA_DEBUG env var is set.
897 *
898 * \param ctx GL context.
899 * \param fmtString printf()-like format string.
900 */
901 void
902 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
903 {
904 char str[MAXSTRING];
905 va_list args;
906 va_start( args, fmtString );
907 (void) _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
908 va_end( args );
909
910 if (ctx)
911 flush_delayed_errors( ctx );
912
913 output_if_debug("Mesa warning", str, GL_TRUE);
914 }
915
916
917 /**
918 * Report an internal implementation problem.
919 * Prints the message to stderr via fprintf().
920 *
921 * \param ctx GL context.
922 * \param fmtString problem description string.
923 */
924 void
925 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
926 {
927 va_list args;
928 char str[MAXSTRING];
929 static int numCalls = 0;
930
931 (void) ctx;
932
933 if (numCalls < 50) {
934 numCalls++;
935
936 va_start( args, fmtString );
937 _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
938 va_end( args );
939 fprintf(stderr, "Mesa %s implementation error: %s\n",
940 MESA_VERSION_STRING, str);
941 fprintf(stderr, "Please report at bugs.freedesktop.org\n");
942 }
943 }
944
945 static GLboolean
946 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
947 {
948 static GLint debug = -1;
949
950 /* Check debug environment variable only once:
951 */
952 if (debug == -1) {
953 const char *debugEnv = _mesa_getenv("MESA_DEBUG");
954
955 #ifdef DEBUG
956 if (debugEnv && strstr(debugEnv, "silent"))
957 debug = GL_FALSE;
958 else
959 debug = GL_TRUE;
960 #else
961 if (debugEnv)
962 debug = GL_TRUE;
963 else
964 debug = GL_FALSE;
965 #endif
966 }
967
968 if (debug) {
969 if (ctx->ErrorValue != error ||
970 ctx->ErrorDebugFmtString != fmtString) {
971 flush_delayed_errors( ctx );
972 ctx->ErrorDebugFmtString = fmtString;
973 ctx->ErrorDebugCount = 0;
974 return GL_TRUE;
975 }
976 ctx->ErrorDebugCount++;
977 }
978 return GL_FALSE;
979 }
980
981
982 /**
983 * Record an OpenGL state error. These usually occur when the user
984 * passes invalid parameters to a GL function.
985 *
986 * If debugging is enabled (either at compile-time via the DEBUG macro, or
987 * run-time via the MESA_DEBUG environment variable), report the error with
988 * _mesa_debug().
989 *
990 * \param ctx the GL context.
991 * \param error the error value.
992 * \param fmtString printf() style format string, followed by optional args
993 */
994 void
995 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
996 {
997 GLboolean do_output, do_log;
998
999 do_output = should_output(ctx, error, fmtString);
1000 do_log = should_log(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB,
1001 API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB);
1002
1003 if (do_output || do_log) {
1004 char s[MAXSTRING], s2[MAXSTRING];
1005 int len;
1006 va_list args;
1007
1008 va_start(args, fmtString);
1009 len = _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
1010 va_end(args);
1011
1012 if (len >= MAXSTRING) {
1013 /* Too long error message. Whoever calls _mesa_error should use
1014 * shorter strings. */
1015 ASSERT(0);
1016 return;
1017 }
1018
1019 len = _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s);
1020 if (len >= MAXSTRING) {
1021 /* Same as above. */
1022 ASSERT(0);
1023 return;
1024 }
1025
1026 /* Print the error to stderr if needed. */
1027 if (do_output) {
1028 output_if_debug("Mesa: User error", s2, GL_TRUE);
1029 }
1030
1031 /* Log the error via ARB_debug_output if needed.*/
1032 if (do_log) {
1033 _mesa_log_msg(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB,
1034 API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB, len, s2);
1035 }
1036 }
1037
1038 /* Set the GL context error state for glGetError. */
1039 _mesa_record_error(ctx, error);
1040 }
1041
1042
1043 /**
1044 * Report debug information. Print error message to stderr via fprintf().
1045 * No-op if DEBUG mode not enabled.
1046 *
1047 * \param ctx GL context.
1048 * \param fmtString printf()-style format string, followed by optional args.
1049 */
1050 void
1051 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
1052 {
1053 #ifdef DEBUG
1054 char s[MAXSTRING];
1055 va_list args;
1056 va_start(args, fmtString);
1057 _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
1058 va_end(args);
1059 output_if_debug("Mesa", s, GL_FALSE);
1060 #endif /* DEBUG */
1061 (void) ctx;
1062 (void) fmtString;
1063 }
1064
1065
1066 /**
1067 * Report debug information from the shader compiler via GL_ARB_debug_output.
1068 *
1069 * \param ctx GL context.
1070 * \param type The namespace to which this message belongs.
1071 * \param id The message ID within the given namespace.
1072 * \param msg The message to output. Need not be null-terminated.
1073 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
1074 */
1075 void
1076 _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint id,
1077 const char *msg, int len )
1078 {
1079 GLenum source = GL_DEBUG_SOURCE_SHADER_COMPILER_ARB,
1080 severity;
1081
1082 switch (type) {
1083 case GL_DEBUG_TYPE_ERROR_ARB:
1084 assert(id < SHADER_ERROR_COUNT);
1085 severity = GL_DEBUG_SEVERITY_HIGH_ARB;
1086 break;
1087 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
1088 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
1089 case GL_DEBUG_TYPE_PORTABILITY_ARB:
1090 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
1091 case GL_DEBUG_TYPE_OTHER_ARB:
1092 assert(0 && "other categories not implemented yet");
1093 default:
1094 _mesa_problem(ctx, "bad enum in _mesa_shader_debug()");
1095 return;
1096 }
1097
1098 if (len < 0)
1099 len = strlen(msg);
1100
1101 /* Truncate the message if necessary. */
1102 if (len >= MAX_DEBUG_MESSAGE_LENGTH)
1103 len = MAX_DEBUG_MESSAGE_LENGTH - 1;
1104
1105 _mesa_log_msg(ctx, source, type, id, severity, len, msg);
1106 }
1107
1108 /*@}*/