3 * Mesa debugging and error handling functions.
7 * Mesa 3-D graphics library
10 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
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.
42 struct gl_client_severity
44 struct simple_node link
;
48 static char out_of_memory
[] = "Debugging error: out of memory";
50 #define enum_is(e, kind1, kind2) \
51 ((e) == GL_DEBUG_##kind1##_##kind2##_ARB || (e) == GL_DONT_CARE)
52 #define severity_is(sev, kind) enum_is(sev, SEVERITY, kind)
53 #define source_is(s, kind) enum_is(s, SOURCE, kind)
54 #define type_is(t, kind) enum_is(t, TYPE, kind)
56 /* Prevent define collision on Windows */
89 enum_to_index(GLenum e
)
92 case GL_DEBUG_SOURCE_APPLICATION_ARB
:
93 return (int)SOURCE_APPLICATION
;
94 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB
:
95 return (int)SOURCE_THIRD_PARTY
;
97 case GL_DEBUG_TYPE_ERROR_ARB
:
98 return (int)TYPE_ERROR
;
99 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB
:
100 return (int)TYPE_DEPRECATED
;
101 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB
:
102 return (int)TYPE_UNDEFINED
;
103 case GL_DEBUG_TYPE_PERFORMANCE_ARB
:
104 return (int)TYPE_PERFORMANCE
;
105 case GL_DEBUG_TYPE_PORTABILITY_ARB
:
106 return (int)TYPE_PORTABILITY
;
107 case GL_DEBUG_TYPE_OTHER_ARB
:
108 return (int)TYPE_OTHER
;
110 case GL_DEBUG_SEVERITY_LOW_ARB
:
111 return (int)SEVERITY_LOW
;
112 case GL_DEBUG_SEVERITY_MEDIUM_ARB
:
113 return (int)SEVERITY_MEDIUM
;
114 case GL_DEBUG_SEVERITY_HIGH_ARB
:
115 return (int)SEVERITY_HIGH
;
118 return (int)TYPE_ANY
;
121 assert(0 && "unreachable");
128 * We store a bitfield in the hash table, with five possible values total.
130 * The ENABLED_BIT's purpose is self-explanatory.
132 * The FOUND_BIT is needed to differentiate the value of DISABLED from
133 * the value returned by HashTableLookup() when it can't find the given key.
135 * The KNOWN_SEVERITY bit is a bit complicated:
137 * A client may call Control() with an array of IDs, then call Control()
138 * on all message IDs of a certain severity, then Insert() one of the
139 * previously specified IDs, giving us a known severity level, then call
140 * Control() on all message IDs of a certain severity level again.
142 * After the first call, those IDs will have a FOUND_BIT, but will not
143 * exist in any severity-specific list, so the second call will not
144 * impact them. This is undesirable but unavoidable given the API:
145 * The only entrypoint that gives a severity for a client-defined ID
146 * is the Insert() call.
148 * For the sake of Control(), we want to maintain the invariant
149 * that an ID will either appear in none of the three severity lists,
150 * or appear once, to minimize pointless duplication and potential surprises.
152 * Because Insert() is the only place that will learn an ID's severity,
153 * it should insert an ID into the appropriate list, but only if the ID
154 * doesn't exist in it or any other list yet. Because searching all three
155 * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
159 ENABLED_BIT
= 1 << 1,
160 KNOWN_SEVERITY
= 1 << 2,
162 /* HashTable reserves zero as a return value meaning 'not found' */
164 DISABLED
= FOUND_BIT
,
165 ENABLED
= ENABLED_BIT
| FOUND_BIT
169 * Returns the state of the given message ID in a client-controlled
171 * 'source', 'type', and 'severity' are array indices like TYPE_ERROR,
175 get_message_state(struct gl_context
*ctx
, int source
, int type
,
176 GLuint id
, int severity
)
178 struct gl_client_namespace
*nspace
=
179 &ctx
->Debug
.ClientIDs
.Namespaces
[source
][type
];
182 /* In addition to not being able to store zero as a value, HashTable also
183 can't use zero as a key. */
185 state
= (uintptr_t)_mesa_HashLookup(nspace
->IDs
, id
);
187 state
= nspace
->ZeroID
;
189 /* Only do this once for each ID. This makes sure the ID exists in,
190 at most, one list, and does not pointlessly appear multiple times. */
191 if (!(state
& KNOWN_SEVERITY
)) {
192 struct gl_client_severity
*entry
;
194 if (state
== NOT_FOUND
) {
195 if (ctx
->Debug
.ClientIDs
.Defaults
[severity
][source
][type
])
201 entry
= malloc(sizeof *entry
);
205 state
|= KNOWN_SEVERITY
;
208 _mesa_HashInsert(nspace
->IDs
, id
, (void*)state
);
210 nspace
->ZeroID
= state
;
213 insert_at_tail(&nspace
->Severity
[severity
], &entry
->link
);
217 return !!(state
& ENABLED_BIT
);
221 * Sets the state of the given message ID in a client-controlled
223 * 'source' and 'type' are array indices like TYPE_ERROR, not GL enums.
226 set_message_state(struct gl_context
*ctx
, int source
, int type
,
227 GLuint id
, GLboolean enabled
)
229 struct gl_client_namespace
*nspace
=
230 &ctx
->Debug
.ClientIDs
.Namespaces
[source
][type
];
233 /* In addition to not being able to store zero as a value, HashTable also
234 can't use zero as a key. */
236 state
= (uintptr_t)_mesa_HashLookup(nspace
->IDs
, id
);
238 state
= nspace
->ZeroID
;
240 if (state
== NOT_FOUND
)
241 state
= enabled
? ENABLED
: DISABLED
;
244 state
|= ENABLED_BIT
;
246 state
&= ~ENABLED_BIT
;
250 _mesa_HashInsert(nspace
->IDs
, id
, (void*)state
);
252 nspace
->ZeroID
= state
;
256 * Whether a debugging message should be logged or not.
257 * For implementation-controlled namespaces, we keep an array
258 * of booleans per namespace, per context, recording whether
259 * each individual message is enabled or not. The message ID
260 * is an index into the namespace's array.
263 should_log(struct gl_context
*ctx
, GLenum source
, GLenum type
,
264 GLuint id
, GLenum severity
)
266 if (source
== GL_DEBUG_SOURCE_APPLICATION_ARB
||
267 source
== GL_DEBUG_SOURCE_THIRD_PARTY_ARB
) {
269 s
= enum_to_index(source
);
270 t
= enum_to_index(type
);
271 sev
= enum_to_index(severity
);
273 return get_message_state(ctx
, s
, t
, sev
, id
);
276 if (type_is(type
, ERROR
)) {
277 if (source_is(source
, API
))
278 return ctx
->Debug
.ApiErrors
[id
];
279 if (source_is(source
, WINDOW_SYSTEM
))
280 return ctx
->Debug
.WinsysErrors
[id
];
281 if (source_is(source
, SHADER_COMPILER
))
282 return ctx
->Debug
.ShaderErrors
[id
];
283 if (source_is(source
, OTHER
))
284 return ctx
->Debug
.OtherErrors
[id
];
287 return (severity
!= GL_DEBUG_SEVERITY_LOW_ARB
);
291 * 'buf' is not necessarily a null-terminated string. When logging, copy
292 * 'len' characters from it, store them in a new, null-terminated string,
293 * and remember the number of bytes used by that string, *including*
294 * the null terminator this time.
297 _mesa_log_msg(struct gl_context
*ctx
, GLenum source
, GLenum type
,
298 GLuint id
, GLenum severity
, GLint len
, const char *buf
)
301 struct gl_debug_msg
*emptySlot
;
303 assert(len
>= 0 && len
< MAX_DEBUG_MESSAGE_LENGTH
);
305 if (!should_log(ctx
, source
, type
, id
, severity
))
308 if (ctx
->Debug
.Callback
) {
309 ctx
->Debug
.Callback(source
, type
, id
, severity
,
310 len
, buf
, ctx
->Debug
.CallbackData
);
314 if (ctx
->Debug
.NumMessages
== MAX_DEBUG_LOGGED_MESSAGES
)
317 nextEmpty
= (ctx
->Debug
.NextMsg
+ ctx
->Debug
.NumMessages
)
318 % MAX_DEBUG_LOGGED_MESSAGES
;
319 emptySlot
= &ctx
->Debug
.Log
[nextEmpty
];
321 assert(!emptySlot
->message
&& !emptySlot
->length
);
323 emptySlot
->message
= malloc(len
+1);
324 if (emptySlot
->message
) {
325 (void) strncpy(emptySlot
->message
, buf
, (size_t)len
);
326 emptySlot
->message
[len
] = '\0';
328 emptySlot
->length
= len
+1;
329 emptySlot
->source
= source
;
330 emptySlot
->type
= type
;
332 emptySlot
->severity
= severity
;
335 emptySlot
->message
= out_of_memory
;
336 emptySlot
->length
= strlen(out_of_memory
)+1;
337 emptySlot
->source
= GL_DEBUG_SOURCE_OTHER_ARB
;
338 emptySlot
->type
= GL_DEBUG_TYPE_ERROR_ARB
;
339 emptySlot
->id
= OTHER_ERROR_OUT_OF_MEMORY
;
340 emptySlot
->severity
= GL_DEBUG_SEVERITY_HIGH_ARB
;
343 if (ctx
->Debug
.NumMessages
== 0)
344 ctx
->Debug
.NextMsgLength
= ctx
->Debug
.Log
[ctx
->Debug
.NextMsg
].length
;
346 ctx
->Debug
.NumMessages
++;
350 * Pop the oldest debug message out of the log.
351 * Writes the message string, including the null terminator, into 'buf',
352 * using up to 'bufSize' bytes. If 'bufSize' is too small, or
353 * if 'buf' is NULL, nothing is written.
355 * Returns the number of bytes written on success, or when 'buf' is NULL,
356 * the number that would have been written. A return value of 0
360 _mesa_get_msg(struct gl_context
*ctx
, GLenum
*source
, GLenum
*type
,
361 GLuint
*id
, GLenum
*severity
, GLsizei bufSize
, char *buf
)
363 struct gl_debug_msg
*msg
;
366 if (ctx
->Debug
.NumMessages
== 0)
369 msg
= &ctx
->Debug
.Log
[ctx
->Debug
.NextMsg
];
370 length
= msg
->length
;
372 assert(length
> 0 && length
== ctx
->Debug
.NextMsgLength
);
374 if (bufSize
< length
&& buf
!= NULL
)
378 *severity
= msg
->severity
;
380 *source
= msg
->source
;
387 assert(msg
->message
[length
-1] == '\0');
388 (void) strncpy(buf
, msg
->message
, (size_t)length
);
391 if (msg
->message
!= (char*)out_of_memory
)
396 ctx
->Debug
.NumMessages
--;
397 ctx
->Debug
.NextMsg
++;
398 ctx
->Debug
.NextMsg
%= MAX_DEBUG_LOGGED_MESSAGES
;
399 ctx
->Debug
.NextMsgLength
= ctx
->Debug
.Log
[ctx
->Debug
.NextMsg
].length
;
405 * Verify that source, type, and severity are valid enums.
406 * glDebugMessageInsertARB only accepts two values for 'source',
407 * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
408 * in any parameter, so handle those cases specially.
411 validate_params(struct gl_context
*ctx
, unsigned caller
,
412 GLenum source
, GLenum type
, GLenum severity
)
417 case GL_DEBUG_SOURCE_APPLICATION_ARB
:
418 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB
:
420 case GL_DEBUG_SOURCE_API_ARB
:
421 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB
:
422 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB
:
423 case GL_DEBUG_SOURCE_OTHER_ARB
:
424 if (caller
!= INSERT
)
427 if (caller
== CONTROL
)
434 case GL_DEBUG_TYPE_ERROR_ARB
:
435 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB
:
436 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB
:
437 case GL_DEBUG_TYPE_PERFORMANCE_ARB
:
438 case GL_DEBUG_TYPE_PORTABILITY_ARB
:
439 case GL_DEBUG_TYPE_OTHER_ARB
:
442 if (caller
== CONTROL
)
449 case GL_DEBUG_SEVERITY_HIGH_ARB
:
450 case GL_DEBUG_SEVERITY_MEDIUM_ARB
:
451 case GL_DEBUG_SEVERITY_LOW_ARB
:
454 if (caller
== CONTROL
)
463 const char *callerstr
;
464 if (caller
== INSERT
)
465 callerstr
= "glDebugMessageInsertARB";
466 else if (caller
== CONTROL
)
467 callerstr
= "glDebugMessageControlARB";
471 _mesa_error( ctx
, GL_INVALID_ENUM
, "bad values passed to %s"
472 "(source=0x%x, type=0x%x, severity=0x%x)", callerstr
,
473 source
, type
, severity
);
479 _mesa_DebugMessageInsertARB(GLenum source
, GLenum type
, GLuint id
,
480 GLenum severity
, GLint length
,
481 const GLcharARB
* buf
)
483 GET_CURRENT_CONTEXT(ctx
);
485 if (!validate_params(ctx
, INSERT
, source
, type
, severity
))
486 return; /* GL_INVALID_ENUM */
489 length
= strlen(buf
);
491 if (length
>= MAX_DEBUG_MESSAGE_LENGTH
) {
492 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDebugMessageInsertARB"
493 "(length=%d, which is not less than "
494 "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length
,
495 MAX_DEBUG_MESSAGE_LENGTH
);
499 _mesa_log_msg(ctx
, source
, type
, id
, severity
, length
, buf
);
503 _mesa_GetDebugMessageLogARB(GLuint count
, GLsizei logSize
, GLenum
* sources
,
504 GLenum
* types
, GLenum
* ids
, GLenum
* severities
,
505 GLsizei
* lengths
, GLcharARB
* messageLog
)
507 GET_CURRENT_CONTEXT(ctx
);
514 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGetDebugMessageLogARB"
515 "(logSize=%d : logSize must not be negative)", logSize
);
519 for (ret
= 0; ret
< count
; ret
++) {
520 GLsizei written
= _mesa_get_msg(ctx
, sources
, types
, ids
, severities
,
521 logSize
, messageLog
);
526 messageLog
+= written
;
548 * 'array' is an array representing a particular debugging-message namespace.
549 * I.e., the set of all API errors, or the set of all Shader Compiler errors.
550 * 'size' is the size of 'array'. 'count' is the size of 'ids', an array
551 * of indices into 'array'. All the elements of 'array' at the indices
552 * listed in 'ids' will be overwritten with the value of 'enabled'.
554 * If 'count' is zero, all elements in 'array' are overwritten with the
555 * value of 'enabled'.
558 control_messages(GLboolean
*array
, GLuint size
,
559 GLsizei count
, const GLuint
*ids
, GLboolean enabled
)
565 for (id
= 0; id
< size
; id
++) {
571 for (i
= 0; i
< count
; i
++) {
572 if (ids
[i
] >= size
) {
573 /* XXX: The spec doesn't say what to do with a non-existent ID. */
576 array
[ids
[i
]] = enabled
;
581 * Set the state of all message IDs found in the given intersection
582 * of 'source', 'type', and 'severity'. Note that all three of these
583 * parameters are array indices, not the corresponding GL enums.
585 * This requires both setting the state of all previously seen message
586 * IDs in the hash table, and setting the default state for all
587 * applicable combinations of source/type/severity, so that all the
588 * yet-unknown message IDs that may be used in the future will be
589 * impacted as if they were already known.
592 control_app_messages_by_group(struct gl_context
*ctx
, int source
, int type
,
593 int severity
, GLboolean enabled
)
595 struct gl_client_debug
*ClientIDs
= &ctx
->Debug
.ClientIDs
;
596 int s
, t
, sev
, smax
, tmax
, sevmax
;
598 if (source
== SOURCE_ANY
) {
605 if (type
== TYPE_ANY
) {
612 if (severity
== SEVERITY_ANY
) {
614 sevmax
= SEVERITY_COUNT
;
619 for (sev
= severity
; sev
< sevmax
; sev
++)
620 for (s
= source
; s
< smax
; s
++)
621 for (t
= type
; t
< tmax
; t
++) {
622 struct simple_node
*node
;
623 struct gl_client_severity
*entry
;
625 /* change the default for IDs we've never seen before. */
626 ClientIDs
->Defaults
[sev
][s
][t
] = enabled
;
628 /* Now change the state of IDs we *have* seen... */
629 foreach(node
, &ClientIDs
->Namespaces
[s
][t
].Severity
[sev
]) {
630 entry
= (struct gl_client_severity
*)node
;
631 set_message_state(ctx
, s
, t
, entry
->ID
, enabled
);
637 * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
638 * require special handling, since the IDs in them are controlled by clients,
639 * not the OpenGL implementation.
641 * 'count' is the length of the array 'ids'. If 'count' is nonzero, all
642 * the given IDs in the namespace defined by 'esource' and 'etype'
645 * If 'count' is zero, this sets the state of all IDs that match
646 * the combination of 'esource', 'etype', and 'eseverity'.
649 control_app_messages(struct gl_context
*ctx
, GLenum esource
, GLenum etype
,
650 GLenum eseverity
, GLsizei count
, const GLuint
*ids
,
653 int source
, type
, severity
;
656 source
= enum_to_index(esource
);
657 type
= enum_to_index(etype
);
658 severity
= enum_to_index(eseverity
);
661 assert(severity
== SEVERITY_ANY
&& type
!= TYPE_ANY
662 && source
!= SOURCE_ANY
);
664 for (i
= 0; i
< count
; i
++)
665 set_message_state(ctx
, source
, type
, ids
[i
], enabled
);
670 control_app_messages_by_group(ctx
, source
, type
, severity
, enabled
);
674 _mesa_DebugMessageControlARB(GLenum source
, GLenum type
, GLenum severity
,
675 GLsizei count
, const GLuint
*ids
,
678 GET_CURRENT_CONTEXT(ctx
);
681 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDebugMessageControlARB"
682 "(count=%d : count must not be negative)", count
);
686 if (!validate_params(ctx
, CONTROL
, source
, type
, severity
))
687 return; /* GL_INVALID_ENUM */
689 if (count
&& (severity
!= GL_DONT_CARE
|| type
== GL_DONT_CARE
690 || source
== GL_DONT_CARE
)) {
691 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDebugMessageControlARB"
692 "(When passing an array of ids, severity must be"
693 " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.");
697 if (source_is(source
, APPLICATION
) || source_is(source
, THIRD_PARTY
))
698 control_app_messages(ctx
, source
, type
, severity
, count
, ids
, enabled
);
700 if (severity_is(severity
, HIGH
)) {
701 if (type_is(type
, ERROR
)) {
702 if (source_is(source
, API
))
703 control_messages(ctx
->Debug
.ApiErrors
, API_ERROR_COUNT
,
704 count
, ids
, enabled
);
705 if (source_is(source
, WINDOW_SYSTEM
))
706 control_messages(ctx
->Debug
.WinsysErrors
, WINSYS_ERROR_COUNT
,
707 count
, ids
, enabled
);
708 if (source_is(source
, SHADER_COMPILER
))
709 control_messages(ctx
->Debug
.ShaderErrors
, SHADER_ERROR_COUNT
,
710 count
, ids
, enabled
);
711 if (source_is(source
, OTHER
))
712 control_messages(ctx
->Debug
.OtherErrors
, OTHER_ERROR_COUNT
,
713 count
, ids
, enabled
);
719 _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback
, const GLvoid
*userParam
)
721 GET_CURRENT_CONTEXT(ctx
);
722 ctx
->Debug
.Callback
= callback
;
723 ctx
->Debug
.CallbackData
= (void *) userParam
;
727 _mesa_init_errors(struct gl_context
*ctx
)
730 struct gl_client_debug
*ClientIDs
= &ctx
->Debug
.ClientIDs
;
732 ctx
->Debug
.Callback
= NULL
;
733 ctx
->Debug
.SyncOutput
= GL_FALSE
;
734 ctx
->Debug
.Log
[0].length
= 0;
735 ctx
->Debug
.NumMessages
= 0;
736 ctx
->Debug
.NextMsg
= 0;
737 ctx
->Debug
.NextMsgLength
= 0;
739 /* Enable all the messages with severity HIGH or MEDIUM by default. */
740 memset(ctx
->Debug
.ApiErrors
, GL_TRUE
, sizeof ctx
->Debug
.ApiErrors
);
741 memset(ctx
->Debug
.WinsysErrors
, GL_TRUE
, sizeof ctx
->Debug
.WinsysErrors
);
742 memset(ctx
->Debug
.ShaderErrors
, GL_TRUE
, sizeof ctx
->Debug
.ShaderErrors
);
743 memset(ctx
->Debug
.OtherErrors
, GL_TRUE
, sizeof ctx
->Debug
.OtherErrors
);
744 memset(ClientIDs
->Defaults
[SEVERITY_HIGH
], GL_TRUE
,
745 sizeof ClientIDs
->Defaults
[SEVERITY_HIGH
]);
746 memset(ClientIDs
->Defaults
[SEVERITY_MEDIUM
], GL_TRUE
,
747 sizeof ClientIDs
->Defaults
[SEVERITY_MEDIUM
]);
748 memset(ClientIDs
->Defaults
[SEVERITY_LOW
], GL_FALSE
,
749 sizeof ClientIDs
->Defaults
[SEVERITY_LOW
]);
751 /* Initialize state for filtering client-provided debug messages. */
752 for (s
= 0; s
< SOURCE_COUNT
; s
++)
753 for (t
= 0; t
< TYPE_COUNT
; t
++) {
754 ClientIDs
->Namespaces
[s
][t
].IDs
= _mesa_NewHashTable();
755 assert(ClientIDs
->Namespaces
[s
][t
].IDs
);
757 for (sev
= 0; sev
< SEVERITY_COUNT
; sev
++)
758 make_empty_list(&ClientIDs
->Namespaces
[s
][t
].Severity
[sev
]);
763 _mesa_free_errors_data(struct gl_context
*ctx
)
766 struct gl_client_debug
*ClientIDs
= &ctx
->Debug
.ClientIDs
;
768 /* Tear down state for filtering client-provided debug messages. */
769 for (s
= 0; s
< SOURCE_COUNT
; s
++)
770 for (t
= 0; t
< TYPE_COUNT
; t
++) {
771 _mesa_DeleteHashTable(ClientIDs
->Namespaces
[s
][t
].IDs
);
772 for (sev
= 0; sev
< SEVERITY_COUNT
; sev
++) {
773 struct simple_node
*node
, *tmp
;
774 struct gl_client_severity
*entry
;
776 foreach_s(node
, tmp
, &ClientIDs
->Namespaces
[s
][t
].Severity
[sev
]) {
777 entry
= (struct gl_client_severity
*)node
;
784 /**********************************************************************/
785 /** \name Diagnostics */
789 output_if_debug(const char *prefixString
, const char *outputString
,
792 static int debug
= -1;
793 static FILE *fout
= NULL
;
795 /* Init the local 'debug' var once.
796 * Note: the _mesa_init_debug() function should have been called
797 * by now so MESA_DEBUG_FLAGS will be initialized.
800 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
801 * etc to the named file. Otherwise, output to stderr.
803 const char *logFile
= _mesa_getenv("MESA_LOG_FILE");
805 fout
= fopen(logFile
, "w");
809 /* in debug builds, print messages unless MESA_DEBUG="silent" */
810 if (MESA_DEBUG_FLAGS
& DEBUG_SILENT
)
815 /* in release builds, be silent unless MESA_DEBUG is set */
816 debug
= _mesa_getenv("MESA_DEBUG") != NULL
;
820 /* Now only print the string if we're required to do so. */
822 fprintf(fout
, "%s: %s", prefixString
, outputString
);
827 #if defined(_WIN32) && !defined(_WIN32_WCE)
828 /* stderr from windows applications without console is not usually
829 * visible, so communicate with the debugger instead */
832 _mesa_snprintf(buf
, sizeof(buf
), "%s: %s%s", prefixString
, outputString
, newline
? "\n" : "");
833 OutputDebugStringA(buf
);
841 * Return string version of GL error code.
844 error_string( GLenum error
)
848 return "GL_NO_ERROR";
849 case GL_INVALID_VALUE
:
850 return "GL_INVALID_VALUE";
851 case GL_INVALID_ENUM
:
852 return "GL_INVALID_ENUM";
853 case GL_INVALID_OPERATION
:
854 return "GL_INVALID_OPERATION";
855 case GL_STACK_OVERFLOW
:
856 return "GL_STACK_OVERFLOW";
857 case GL_STACK_UNDERFLOW
:
858 return "GL_STACK_UNDERFLOW";
859 case GL_OUT_OF_MEMORY
:
860 return "GL_OUT_OF_MEMORY";
861 case GL_TABLE_TOO_LARGE
:
862 return "GL_TABLE_TOO_LARGE";
863 case GL_INVALID_FRAMEBUFFER_OPERATION_EXT
:
864 return "GL_INVALID_FRAMEBUFFER_OPERATION";
872 * When a new type of error is recorded, print a message describing
873 * previous errors which were accumulated.
876 flush_delayed_errors( struct gl_context
*ctx
)
878 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
880 if (ctx
->ErrorDebugCount
) {
881 _mesa_snprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, "%d similar %s errors",
882 ctx
->ErrorDebugCount
,
883 error_string(ctx
->ErrorValue
));
885 output_if_debug("Mesa", s
, GL_TRUE
);
887 ctx
->ErrorDebugCount
= 0;
893 * Report a warning (a recoverable error condition) to stderr if
894 * either DEBUG is defined or the MESA_DEBUG env var is set.
896 * \param ctx GL context.
897 * \param fmtString printf()-like format string.
900 _mesa_warning( struct gl_context
*ctx
, const char *fmtString
, ... )
902 char str
[MAX_DEBUG_MESSAGE_LENGTH
];
904 va_start( args
, fmtString
);
905 (void) _mesa_vsnprintf( str
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
909 flush_delayed_errors( ctx
);
911 output_if_debug("Mesa warning", str
, GL_TRUE
);
916 * Report an internal implementation problem.
917 * Prints the message to stderr via fprintf().
919 * \param ctx GL context.
920 * \param fmtString problem description string.
923 _mesa_problem( const struct gl_context
*ctx
, const char *fmtString
, ... )
926 char str
[MAX_DEBUG_MESSAGE_LENGTH
];
927 static int numCalls
= 0;
934 va_start( args
, fmtString
);
935 _mesa_vsnprintf( str
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
937 fprintf(stderr
, "Mesa %s implementation error: %s\n",
938 MESA_VERSION_STRING
, str
);
939 fprintf(stderr
, "Please report at bugs.freedesktop.org\n");
944 should_output(struct gl_context
*ctx
, GLenum error
, const char *fmtString
)
946 static GLint debug
= -1;
948 /* Check debug environment variable only once:
951 const char *debugEnv
= _mesa_getenv("MESA_DEBUG");
954 if (debugEnv
&& strstr(debugEnv
, "silent"))
967 if (ctx
->ErrorValue
!= error
||
968 ctx
->ErrorDebugFmtString
!= fmtString
) {
969 flush_delayed_errors( ctx
);
970 ctx
->ErrorDebugFmtString
= fmtString
;
971 ctx
->ErrorDebugCount
= 0;
974 ctx
->ErrorDebugCount
++;
981 * Record an OpenGL state error. These usually occur when the user
982 * passes invalid parameters to a GL function.
984 * If debugging is enabled (either at compile-time via the DEBUG macro, or
985 * run-time via the MESA_DEBUG environment variable), report the error with
988 * \param ctx the GL context.
989 * \param error the error value.
990 * \param fmtString printf() style format string, followed by optional args
993 _mesa_error( struct gl_context
*ctx
, GLenum error
, const char *fmtString
, ... )
995 GLboolean do_output
, do_log
;
997 do_output
= should_output(ctx
, error
, fmtString
);
998 do_log
= should_log(ctx
, GL_DEBUG_SOURCE_API_ARB
, GL_DEBUG_TYPE_ERROR_ARB
,
999 API_ERROR_UNKNOWN
, GL_DEBUG_SEVERITY_HIGH_ARB
);
1001 if (do_output
|| do_log
) {
1002 char s
[MAX_DEBUG_MESSAGE_LENGTH
], s2
[MAX_DEBUG_MESSAGE_LENGTH
];
1006 va_start(args
, fmtString
);
1007 len
= _mesa_vsnprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
1010 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
) {
1011 /* Too long error message. Whoever calls _mesa_error should use
1012 * shorter strings. */
1017 len
= _mesa_snprintf(s2
, MAX_DEBUG_MESSAGE_LENGTH
, "%s in %s",
1018 error_string(error
), s
);
1019 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
) {
1020 /* Same as above. */
1025 /* Print the error to stderr if needed. */
1027 output_if_debug("Mesa: User error", s2
, GL_TRUE
);
1030 /* Log the error via ARB_debug_output if needed.*/
1032 _mesa_log_msg(ctx
, GL_DEBUG_SOURCE_API_ARB
, GL_DEBUG_TYPE_ERROR_ARB
,
1033 API_ERROR_UNKNOWN
, GL_DEBUG_SEVERITY_HIGH_ARB
, len
, s2
);
1037 /* Set the GL context error state for glGetError. */
1038 _mesa_record_error(ctx
, error
);
1043 * Report debug information. Print error message to stderr via fprintf().
1044 * No-op if DEBUG mode not enabled.
1046 * \param ctx GL context.
1047 * \param fmtString printf()-style format string, followed by optional args.
1050 _mesa_debug( const struct gl_context
*ctx
, const char *fmtString
, ... )
1053 char s
[MAX_DEBUG_MESSAGE_LENGTH
];
1055 va_start(args
, fmtString
);
1056 _mesa_vsnprintf(s
, MAX_DEBUG_MESSAGE_LENGTH
, fmtString
, args
);
1058 output_if_debug("Mesa", s
, GL_FALSE
);
1066 * Report debug information from the shader compiler via GL_ARB_debug_output.
1068 * \param ctx GL context.
1069 * \param type The namespace to which this message belongs.
1070 * \param id The message ID within the given namespace.
1071 * \param msg The message to output. Need not be null-terminated.
1072 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
1075 _mesa_shader_debug( struct gl_context
*ctx
, GLenum type
, GLuint id
,
1076 const char *msg
, int len
)
1078 GLenum source
= GL_DEBUG_SOURCE_SHADER_COMPILER_ARB
,
1082 case GL_DEBUG_TYPE_ERROR_ARB
:
1083 assert(id
< SHADER_ERROR_COUNT
);
1084 severity
= GL_DEBUG_SEVERITY_HIGH_ARB
;
1086 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB
:
1087 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB
:
1088 case GL_DEBUG_TYPE_PORTABILITY_ARB
:
1089 case GL_DEBUG_TYPE_PERFORMANCE_ARB
:
1090 case GL_DEBUG_TYPE_OTHER_ARB
:
1091 assert(0 && "other categories not implemented yet");
1093 _mesa_problem(ctx
, "bad enum in _mesa_shader_debug()");
1100 /* Truncate the message if necessary. */
1101 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
)
1102 len
= MAX_DEBUG_MESSAGE_LENGTH
- 1;
1104 _mesa_log_msg(ctx
, source
, type
, id
, severity
, len
, msg
);