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
enum_to_index(GLenum e)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
get_message_state(struct gl_context * ctx,int source,int type,GLuint id,int severity)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
set_message_state(struct gl_context * ctx,int source,int type,GLuint id,GLboolean enabled)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
should_log(struct gl_context * ctx,GLenum source,GLenum type,GLuint id,GLenum severity)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
_mesa_log_msg(struct gl_context * ctx,GLenum source,GLenum type,GLuint id,GLenum severity,GLint len,const char * buf)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
_mesa_get_msg(struct gl_context * ctx,GLenum * source,GLenum * type,GLuint * id,GLenum * severity,GLsizei bufSize,char * buf)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
validate_params(struct gl_context * ctx,unsigned caller,GLenum source,GLenum type,GLenum severity)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 static void GLAPIENTRY
_mesa_DebugMessageInsertARB(GLenum source,GLenum type,GLuint id,GLenum severity,GLint length,const GLcharARB * buf)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 static GLuint GLAPIENTRY
_mesa_GetDebugMessageLogARB(GLuint count,GLsizei logSize,GLenum * sources,GLenum * types,GLenum * ids,GLenum * severities,GLsizei * lengths,GLcharARB * messageLog)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
control_messages(GLboolean * array,GLuint size,GLsizei count,const GLuint * ids,GLboolean enabled)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
control_app_messages_by_group(struct gl_context * ctx,int source,int type,int severity,GLboolean enabled)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
control_app_messages(struct gl_context * ctx,GLenum esource,GLenum etype,GLenum eseverity,GLsizei count,const GLuint * ids,GLboolean enabled)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 static void GLAPIENTRY
_mesa_DebugMessageControlARB(GLenum source,GLenum type,GLenum severity,GLsizei count,const GLuint * ids,GLboolean enabled)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 static void GLAPIENTRY
_mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback,const GLvoid * userParam)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
_mesa_init_errors_dispatch(struct _glapi_table * disp)729 _mesa_init_errors_dispatch(struct _glapi_table *disp)
730 {
731 SET_DebugMessageCallbackARB(disp, _mesa_DebugMessageCallbackARB);
732 SET_DebugMessageControlARB(disp, _mesa_DebugMessageControlARB);
733 SET_DebugMessageInsertARB(disp, _mesa_DebugMessageInsertARB);
734 SET_GetDebugMessageLogARB(disp, _mesa_GetDebugMessageLogARB);
735 }
736
737 void
_mesa_init_errors(struct gl_context * ctx)738 _mesa_init_errors(struct gl_context *ctx)
739 {
740 int s, t, sev;
741 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
742
743 ctx->Debug.Callback = NULL;
744 ctx->Debug.SyncOutput = GL_FALSE;
745 ctx->Debug.Log[0].length = 0;
746 ctx->Debug.NumMessages = 0;
747 ctx->Debug.NextMsg = 0;
748 ctx->Debug.NextMsgLength = 0;
749
750 /* Enable all the messages with severity HIGH or MEDIUM by default. */
751 memset(ctx->Debug.ApiErrors, GL_TRUE, sizeof ctx->Debug.ApiErrors);
752 memset(ctx->Debug.WinsysErrors, GL_TRUE, sizeof ctx->Debug.WinsysErrors);
753 memset(ctx->Debug.ShaderErrors, GL_TRUE, sizeof ctx->Debug.ShaderErrors);
754 memset(ctx->Debug.OtherErrors, GL_TRUE, sizeof ctx->Debug.OtherErrors);
755 memset(ClientIDs->Defaults[SEVERITY_HIGH], GL_TRUE,
756 sizeof ClientIDs->Defaults[SEVERITY_HIGH]);
757 memset(ClientIDs->Defaults[SEVERITY_MEDIUM], GL_TRUE,
758 sizeof ClientIDs->Defaults[SEVERITY_MEDIUM]);
759 memset(ClientIDs->Defaults[SEVERITY_LOW], GL_FALSE,
760 sizeof ClientIDs->Defaults[SEVERITY_LOW]);
761
762 /* Initialize state for filtering client-provided debug messages. */
763 for (s = 0; s < SOURCE_COUNT; s++)
764 for (t = 0; t < TYPE_COUNT; t++) {
765 ClientIDs->Namespaces[s][t].IDs = _mesa_NewHashTable();
766 assert(ClientIDs->Namespaces[s][t].IDs);
767
768 for (sev = 0; sev < SEVERITY_COUNT; sev++)
769 make_empty_list(&ClientIDs->Namespaces[s][t].Severity[sev]);
770 }
771 }
772
773 void
_mesa_free_errors_data(struct gl_context * ctx)774 _mesa_free_errors_data(struct gl_context *ctx)
775 {
776 int s, t, sev;
777 struct gl_client_debug *ClientIDs = &ctx->Debug.ClientIDs;
778
779 /* Tear down state for filtering client-provided debug messages. */
780 for (s = 0; s < SOURCE_COUNT; s++)
781 for (t = 0; t < TYPE_COUNT; t++) {
782 _mesa_DeleteHashTable(ClientIDs->Namespaces[s][t].IDs);
783 for (sev = 0; sev < SEVERITY_COUNT; sev++) {
784 struct simple_node *node, *tmp;
785 struct gl_client_severity *entry;
786
787 foreach_s(node, tmp, &ClientIDs->Namespaces[s][t].Severity[sev]) {
788 entry = (struct gl_client_severity *)node;
789 FREE(entry);
790 }
791 }
792 }
793 }
794
795 /**********************************************************************/
796 /** \name Diagnostics */
797 /*@{*/
798
799 static void
output_if_debug(const char * prefixString,const char * outputString,GLboolean newline)800 output_if_debug(const char *prefixString, const char *outputString,
801 GLboolean newline)
802 {
803 static int debug = -1;
804 static FILE *fout = NULL;
805
806 /* Init the local 'debug' var once.
807 * Note: the _mesa_init_debug() function should have been called
808 * by now so MESA_DEBUG_FLAGS will be initialized.
809 */
810 if (debug == -1) {
811 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
812 * etc to the named file. Otherwise, output to stderr.
813 */
814 const char *logFile = _mesa_getenv("MESA_LOG_FILE");
815 if (logFile)
816 fout = fopen(logFile, "w");
817 if (!fout)
818 fout = stderr;
819 #ifdef DEBUG
820 /* in debug builds, print messages unless MESA_DEBUG="silent" */
821 if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
822 debug = 0;
823 else
824 debug = 1;
825 #else
826 /* in release builds, be silent unless MESA_DEBUG is set */
827 debug = _mesa_getenv("MESA_DEBUG") != NULL;
828 #endif
829 }
830
831 /* Now only print the string if we're required to do so. */
832 if (debug) {
833 fprintf(fout, "%s: %s", prefixString, outputString);
834 if (newline)
835 fprintf(fout, "\n");
836 fflush(fout);
837
838 #if defined(_WIN32) && !defined(_WIN32_WCE)
839 /* stderr from windows applications without console is not usually
840 * visible, so communicate with the debugger instead */
841 {
842 char buf[4096];
843 _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
844 OutputDebugStringA(buf);
845 }
846 #endif
847 }
848 }
849
850
851 /**
852 * Return string version of GL error code.
853 */
854 static const char *
error_string(GLenum error)855 error_string( GLenum error )
856 {
857 switch (error) {
858 case GL_NO_ERROR:
859 return "GL_NO_ERROR";
860 case GL_INVALID_VALUE:
861 return "GL_INVALID_VALUE";
862 case GL_INVALID_ENUM:
863 return "GL_INVALID_ENUM";
864 case GL_INVALID_OPERATION:
865 return "GL_INVALID_OPERATION";
866 case GL_STACK_OVERFLOW:
867 return "GL_STACK_OVERFLOW";
868 case GL_STACK_UNDERFLOW:
869 return "GL_STACK_UNDERFLOW";
870 case GL_OUT_OF_MEMORY:
871 return "GL_OUT_OF_MEMORY";
872 case GL_TABLE_TOO_LARGE:
873 return "GL_TABLE_TOO_LARGE";
874 case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
875 return "GL_INVALID_FRAMEBUFFER_OPERATION";
876 default:
877 return "unknown";
878 }
879 }
880
881
882 /**
883 * When a new type of error is recorded, print a message describing
884 * previous errors which were accumulated.
885 */
886 static void
flush_delayed_errors(struct gl_context * ctx)887 flush_delayed_errors( struct gl_context *ctx )
888 {
889 char s[MAXSTRING];
890
891 if (ctx->ErrorDebugCount) {
892 _mesa_snprintf(s, MAXSTRING, "%d similar %s errors",
893 ctx->ErrorDebugCount,
894 error_string(ctx->ErrorValue));
895
896 output_if_debug("Mesa", s, GL_TRUE);
897
898 ctx->ErrorDebugCount = 0;
899 }
900 }
901
902
903 /**
904 * Report a warning (a recoverable error condition) to stderr if
905 * either DEBUG is defined or the MESA_DEBUG env var is set.
906 *
907 * \param ctx GL context.
908 * \param fmtString printf()-like format string.
909 */
910 void
_mesa_warning(struct gl_context * ctx,const char * fmtString,...)911 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
912 {
913 char str[MAXSTRING];
914 va_list args;
915 va_start( args, fmtString );
916 (void) _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
917 va_end( args );
918
919 if (ctx)
920 flush_delayed_errors( ctx );
921
922 output_if_debug("Mesa warning", str, GL_TRUE);
923 }
924
925
926 /**
927 * Report an internal implementation problem.
928 * Prints the message to stderr via fprintf().
929 *
930 * \param ctx GL context.
931 * \param fmtString problem description string.
932 */
933 void
_mesa_problem(const struct gl_context * ctx,const char * fmtString,...)934 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
935 {
936 va_list args;
937 char str[MAXSTRING];
938 static int numCalls = 0;
939
940 (void) ctx;
941
942 if (numCalls < 50) {
943 numCalls++;
944
945 va_start( args, fmtString );
946 _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
947 va_end( args );
948 fprintf(stderr, "Mesa %s implementation error: %s\n",
949 MESA_VERSION_STRING, str);
950 fprintf(stderr, "Please report at bugs.freedesktop.org\n");
951 }
952 }
953
954 static GLboolean
should_output(struct gl_context * ctx,GLenum error,const char * fmtString)955 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
956 {
957 static GLint debug = -1;
958
959 /* Check debug environment variable only once:
960 */
961 if (debug == -1) {
962 const char *debugEnv = _mesa_getenv("MESA_DEBUG");
963
964 #ifdef DEBUG
965 if (debugEnv && strstr(debugEnv, "silent"))
966 debug = GL_FALSE;
967 else
968 debug = GL_TRUE;
969 #else
970 if (debugEnv)
971 debug = GL_TRUE;
972 else
973 debug = GL_FALSE;
974 #endif
975 }
976
977 if (debug) {
978 if (ctx->ErrorValue != error ||
979 ctx->ErrorDebugFmtString != fmtString) {
980 flush_delayed_errors( ctx );
981 ctx->ErrorDebugFmtString = fmtString;
982 ctx->ErrorDebugCount = 0;
983 return GL_TRUE;
984 }
985 ctx->ErrorDebugCount++;
986 }
987 return GL_FALSE;
988 }
989
990
991 /**
992 * Record an OpenGL state error. These usually occur when the user
993 * passes invalid parameters to a GL function.
994 *
995 * If debugging is enabled (either at compile-time via the DEBUG macro, or
996 * run-time via the MESA_DEBUG environment variable), report the error with
997 * _mesa_debug().
998 *
999 * \param ctx the GL context.
1000 * \param error the error value.
1001 * \param fmtString printf() style format string, followed by optional args
1002 */
1003 void
_mesa_error(struct gl_context * ctx,GLenum error,const char * fmtString,...)1004 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
1005 {
1006 GLboolean do_output, do_log;
1007
1008 do_output = should_output(ctx, error, fmtString);
1009 do_log = should_log(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB,
1010 API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB);
1011
1012 if (do_output || do_log) {
1013 char s[MAXSTRING], s2[MAXSTRING];
1014 int len;
1015 va_list args;
1016
1017 va_start(args, fmtString);
1018 len = _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
1019 va_end(args);
1020
1021 if (len >= MAXSTRING) {
1022 /* Too long error message. Whoever calls _mesa_error should use
1023 * shorter strings. */
1024 ASSERT(0);
1025 return;
1026 }
1027
1028 len = _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s);
1029 if (len >= MAXSTRING) {
1030 /* Same as above. */
1031 ASSERT(0);
1032 return;
1033 }
1034
1035 /* Print the error to stderr if needed. */
1036 if (do_output) {
1037 output_if_debug("Mesa: User error", s2, GL_TRUE);
1038 }
1039
1040 /* Log the error via ARB_debug_output if needed.*/
1041 if (do_log) {
1042 _mesa_log_msg(ctx, GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_ERROR_ARB,
1043 API_ERROR_UNKNOWN, GL_DEBUG_SEVERITY_HIGH_ARB, len, s2);
1044 }
1045 }
1046
1047 /* Set the GL context error state for glGetError. */
1048 _mesa_record_error(ctx, error);
1049 }
1050
1051
1052 /**
1053 * Report debug information. Print error message to stderr via fprintf().
1054 * No-op if DEBUG mode not enabled.
1055 *
1056 * \param ctx GL context.
1057 * \param fmtString printf()-style format string, followed by optional args.
1058 */
1059 void
_mesa_debug(const struct gl_context * ctx,const char * fmtString,...)1060 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
1061 {
1062 #ifdef DEBUG
1063 char s[MAXSTRING];
1064 va_list args;
1065 va_start(args, fmtString);
1066 _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
1067 va_end(args);
1068 output_if_debug("Mesa", s, GL_FALSE);
1069 #endif /* DEBUG */
1070 (void) ctx;
1071 (void) fmtString;
1072 }
1073
1074
1075 /**
1076 * Report debug information from the shader compiler via GL_ARB_debug_output.
1077 *
1078 * \param ctx GL context.
1079 * \param type The namespace to which this message belongs.
1080 * \param id The message ID within the given namespace.
1081 * \param msg The message to output. Need not be null-terminated.
1082 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
1083 */
1084 void
_mesa_shader_debug(struct gl_context * ctx,GLenum type,GLuint id,const char * msg,int len)1085 _mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint id,
1086 const char *msg, int len )
1087 {
1088 GLenum source = GL_DEBUG_SOURCE_SHADER_COMPILER_ARB,
1089 severity;
1090
1091 switch (type) {
1092 case GL_DEBUG_TYPE_ERROR_ARB:
1093 assert(id < SHADER_ERROR_COUNT);
1094 severity = GL_DEBUG_SEVERITY_HIGH_ARB;
1095 break;
1096 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
1097 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
1098 case GL_DEBUG_TYPE_PORTABILITY_ARB:
1099 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
1100 case GL_DEBUG_TYPE_OTHER_ARB:
1101 assert(0 && "other categories not implemented yet");
1102 default:
1103 _mesa_problem(ctx, "bad enum in _mesa_shader_debug()");
1104 return;
1105 }
1106
1107 if (len < 0)
1108 len = strlen(msg);
1109
1110 /* Truncate the message if necessary. */
1111 if (len >= MAX_DEBUG_MESSAGE_LENGTH)
1112 len = MAX_DEBUG_MESSAGE_LENGTH - 1;
1113
1114 _mesa_log_msg(ctx, source, type, id, severity, len, msg);
1115 }
1116
1117 /*@}*/
1118