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.
41 #define MAXSTRING MAX_DEBUG_MESSAGE_LENGTH
44 struct gl_client_severity
46 struct simple_node link
;
50 static char out_of_memory
[] = "Debugging error: out of memory";
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)
58 /* Prevent define collision on Windows */
91 enum_to_index(GLenum 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
;
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
;
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
;
120 return (int)TYPE_ANY
;
123 assert(0 && "unreachable");
130 * We store a bitfield in the hash table, with five possible values total.
132 * The ENABLED_BIT's purpose is self-explanatory.
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.
137 * The KNOWN_SEVERITY bit is a bit complicated:
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.
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.
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.
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.
161 ENABLED_BIT
= 1 << 1,
162 KNOWN_SEVERITY
= 1 << 2,
164 /* HashTable reserves zero as a return value meaning 'not found' */
166 DISABLED
= FOUND_BIT
,
167 ENABLED
= ENABLED_BIT
| FOUND_BIT
171 * Returns the state of the given message ID in a client-controlled
173 * 'source', 'type', and 'severity' are array indices like TYPE_ERROR,
177 get_message_state(struct gl_context
*ctx
, int source
, int type
,
178 GLuint id
, int severity
)
180 struct gl_client_namespace
*nspace
=
181 &ctx
->Debug
.ClientIDs
.Namespaces
[source
][type
];
184 /* In addition to not being able to store zero as a value, HashTable also
185 can't use zero as a key. */
187 state
= (uintptr_t)_mesa_HashLookup(nspace
->IDs
, id
);
189 state
= nspace
->ZeroID
;
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
;
196 if (state
== NOT_FOUND
) {
197 if (ctx
->Debug
.ClientIDs
.Defaults
[severity
][source
][type
])
203 entry
= malloc(sizeof *entry
);
207 state
|= KNOWN_SEVERITY
;
210 _mesa_HashInsert(nspace
->IDs
, id
, (void*)state
);
212 nspace
->ZeroID
= state
;
215 insert_at_tail(&nspace
->Severity
[severity
], &entry
->link
);
219 return !!(state
& ENABLED_BIT
);
223 * Sets the state of the given message ID in a client-controlled
225 * 'source' and 'type' are array indices like TYPE_ERROR, not GL enums.
228 set_message_state(struct gl_context
*ctx
, int source
, int type
,
229 GLuint id
, GLboolean enabled
)
231 struct gl_client_namespace
*nspace
=
232 &ctx
->Debug
.ClientIDs
.Namespaces
[source
][type
];
235 /* In addition to not being able to store zero as a value, HashTable also
236 can't use zero as a key. */
238 state
= (uintptr_t)_mesa_HashLookup(nspace
->IDs
, id
);
240 state
= nspace
->ZeroID
;
242 if (state
== NOT_FOUND
)
243 state
= enabled
? ENABLED
: DISABLED
;
246 state
|= ENABLED_BIT
;
248 state
&= ~ENABLED_BIT
;
252 _mesa_HashInsert(nspace
->IDs
, id
, (void*)state
);
254 nspace
->ZeroID
= state
;
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.
265 should_log(struct gl_context
*ctx
, GLenum source
, GLenum type
,
266 GLuint id
, GLenum severity
)
268 if (source
== GL_DEBUG_SOURCE_APPLICATION_ARB
||
269 source
== GL_DEBUG_SOURCE_THIRD_PARTY_ARB
) {
271 s
= enum_to_index(source
);
272 t
= enum_to_index(type
);
273 sev
= enum_to_index(severity
);
275 return get_message_state(ctx
, s
, t
, sev
, id
);
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
];
289 return (severity
!= GL_DEBUG_SEVERITY_LOW_ARB
);
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.
299 _mesa_log_msg(struct gl_context
*ctx
, GLenum source
, GLenum type
,
300 GLuint id
, GLenum severity
, GLint len
, const char *buf
)
303 struct gl_debug_msg
*emptySlot
;
305 assert(len
>= 0 && len
< MAX_DEBUG_MESSAGE_LENGTH
);
307 if (!should_log(ctx
, source
, type
, id
, severity
))
310 if (ctx
->Debug
.Callback
) {
311 ctx
->Debug
.Callback(source
, type
, id
, severity
,
312 len
, buf
, ctx
->Debug
.CallbackData
);
316 if (ctx
->Debug
.NumMessages
== MAX_DEBUG_LOGGED_MESSAGES
)
319 nextEmpty
= (ctx
->Debug
.NextMsg
+ ctx
->Debug
.NumMessages
)
320 % MAX_DEBUG_LOGGED_MESSAGES
;
321 emptySlot
= &ctx
->Debug
.Log
[nextEmpty
];
323 assert(!emptySlot
->message
&& !emptySlot
->length
);
325 emptySlot
->message
= MALLOC(len
+1);
326 if (emptySlot
->message
) {
327 (void) strncpy(emptySlot
->message
, buf
, (size_t)len
);
328 emptySlot
->message
[len
] = '\0';
330 emptySlot
->length
= len
+1;
331 emptySlot
->source
= source
;
332 emptySlot
->type
= type
;
334 emptySlot
->severity
= severity
;
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
;
345 if (ctx
->Debug
.NumMessages
== 0)
346 ctx
->Debug
.NextMsgLength
= ctx
->Debug
.Log
[ctx
->Debug
.NextMsg
].length
;
348 ctx
->Debug
.NumMessages
++;
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.
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
362 _mesa_get_msg(struct gl_context
*ctx
, GLenum
*source
, GLenum
*type
,
363 GLuint
*id
, GLenum
*severity
, GLsizei bufSize
, char *buf
)
365 struct gl_debug_msg
*msg
;
368 if (ctx
->Debug
.NumMessages
== 0)
371 msg
= &ctx
->Debug
.Log
[ctx
->Debug
.NextMsg
];
372 length
= msg
->length
;
374 assert(length
> 0 && length
== ctx
->Debug
.NextMsgLength
);
376 if (bufSize
< length
&& buf
!= NULL
)
380 *severity
= msg
->severity
;
382 *source
= msg
->source
;
389 assert(msg
->message
[length
-1] == '\0');
390 (void) strncpy(buf
, msg
->message
, (size_t)length
);
393 if (msg
->message
!= (char*)out_of_memory
)
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
;
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.
413 validate_params(struct gl_context
*ctx
, unsigned caller
,
414 GLenum source
, GLenum type
, GLenum severity
)
419 case GL_DEBUG_SOURCE_APPLICATION_ARB
:
420 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB
:
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
)
429 if (caller
== CONTROL
)
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
:
444 if (caller
== CONTROL
)
451 case GL_DEBUG_SEVERITY_HIGH_ARB
:
452 case GL_DEBUG_SEVERITY_MEDIUM_ARB
:
453 case GL_DEBUG_SEVERITY_LOW_ARB
:
456 if (caller
== CONTROL
)
465 const char *callerstr
;
466 if (caller
== INSERT
)
467 callerstr
= "glDebugMessageInsertARB";
468 else if (caller
== CONTROL
)
469 callerstr
= "glDebugMessageControlARB";
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
);
480 static void GLAPIENTRY
481 _mesa_DebugMessageInsertARB(GLenum source
, GLenum type
, GLuint id
,
482 GLenum severity
, GLint length
,
483 const GLcharARB
* buf
)
485 GET_CURRENT_CONTEXT(ctx
);
487 if (!validate_params(ctx
, INSERT
, source
, type
, severity
))
488 return; /* GL_INVALID_ENUM */
491 length
= strlen(buf
);
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
);
501 _mesa_log_msg(ctx
, source
, type
, id
, severity
, length
, buf
);
504 static GLuint GLAPIENTRY
505 _mesa_GetDebugMessageLogARB(GLuint count
, GLsizei logSize
, GLenum
* sources
,
506 GLenum
* types
, GLenum
* ids
, GLenum
* severities
,
507 GLsizei
* lengths
, GLcharARB
* messageLog
)
509 GET_CURRENT_CONTEXT(ctx
);
516 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGetDebugMessageLogARB"
517 "(logSize=%d : logSize must not be negative)", logSize
);
521 for (ret
= 0; ret
< count
; ret
++) {
522 GLsizei written
= _mesa_get_msg(ctx
, sources
, types
, ids
, severities
,
523 logSize
, messageLog
);
528 messageLog
+= written
;
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'.
556 * If 'count' is zero, all elements in 'array' are overwritten with the
557 * value of 'enabled'.
560 control_messages(GLboolean
*array
, GLuint size
,
561 GLsizei count
, const GLuint
*ids
, GLboolean enabled
)
567 for (id
= 0; id
< size
; id
++) {
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. */
578 array
[ids
[i
]] = enabled
;
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.
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.
594 control_app_messages_by_group(struct gl_context
*ctx
, int source
, int type
,
595 int severity
, GLboolean enabled
)
597 struct gl_client_debug
*ClientIDs
= &ctx
->Debug
.ClientIDs
;
598 int s
, t
, sev
, smax
, tmax
, sevmax
;
600 if (source
== SOURCE_ANY
) {
607 if (type
== TYPE_ANY
) {
614 if (severity
== SEVERITY_ANY
) {
616 sevmax
= SEVERITY_COUNT
;
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
;
627 /* change the default for IDs we've never seen before. */
628 ClientIDs
->Defaults
[sev
][s
][t
] = enabled
;
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
);
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.
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'
647 * If 'count' is zero, this sets the state of all IDs that match
648 * the combination of 'esource', 'etype', and 'eseverity'.
651 control_app_messages(struct gl_context
*ctx
, GLenum esource
, GLenum etype
,
652 GLenum eseverity
, GLsizei count
, const GLuint
*ids
,
655 int source
, type
, severity
;
658 source
= enum_to_index(esource
);
659 type
= enum_to_index(etype
);
660 severity
= enum_to_index(eseverity
);
663 assert(severity
== SEVERITY_ANY
&& type
!= TYPE_ANY
664 && source
!= SOURCE_ANY
);
666 for (i
= 0; i
< count
; i
++)
667 set_message_state(ctx
, source
, type
, ids
[i
], enabled
);
672 control_app_messages_by_group(ctx
, source
, type
, severity
, enabled
);
675 static void GLAPIENTRY
676 _mesa_DebugMessageControlARB(GLenum source
, GLenum type
, GLenum severity
,
677 GLsizei count
, const GLuint
*ids
,
680 GET_CURRENT_CONTEXT(ctx
);
683 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDebugMessageControlARB"
684 "(count=%d : count must not be negative)", count
);
688 if (!validate_params(ctx
, CONTROL
, source
, type
, severity
))
689 return; /* GL_INVALID_ENUM */
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.");
699 if (source_is(source
, APPLICATION
) || source_is(source
, THIRD_PARTY
))
700 control_app_messages(ctx
, source
, type
, severity
, count
, ids
, enabled
);
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
);
720 static void GLAPIENTRY
721 _mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback
, const GLvoid
*userParam
)
723 GET_CURRENT_CONTEXT(ctx
);
724 ctx
->Debug
.Callback
= callback
;
725 ctx
->Debug
.CallbackData
= (void *) userParam
;
729 _mesa_init_errors_dispatch(struct _glapi_table
*disp
)
731 SET_DebugMessageCallbackARB(disp
, _mesa_DebugMessageCallbackARB
);
732 SET_DebugMessageControlARB(disp
, _mesa_DebugMessageControlARB
);
733 SET_DebugMessageInsertARB(disp
, _mesa_DebugMessageInsertARB
);
734 SET_GetDebugMessageLogARB(disp
, _mesa_GetDebugMessageLogARB
);
738 _mesa_init_errors(struct gl_context
*ctx
)
741 struct gl_client_debug
*ClientIDs
= &ctx
->Debug
.ClientIDs
;
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;
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
]);
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
);
768 for (sev
= 0; sev
< SEVERITY_COUNT
; sev
++)
769 make_empty_list(&ClientIDs
->Namespaces
[s
][t
].Severity
[sev
]);
774 _mesa_free_errors_data(struct gl_context
*ctx
)
777 struct gl_client_debug
*ClientIDs
= &ctx
->Debug
.ClientIDs
;
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
;
787 foreach_s(node
, tmp
, &ClientIDs
->Namespaces
[s
][t
].Severity
[sev
]) {
788 entry
= (struct gl_client_severity
*)node
;
795 /**********************************************************************/
796 /** \name Diagnostics */
800 output_if_debug(const char *prefixString
, const char *outputString
,
803 static int debug
= -1;
804 static FILE *fout
= NULL
;
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.
811 /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
812 * etc to the named file. Otherwise, output to stderr.
814 const char *logFile
= _mesa_getenv("MESA_LOG_FILE");
816 fout
= fopen(logFile
, "w");
820 /* in debug builds, print messages unless MESA_DEBUG="silent" */
821 if (MESA_DEBUG_FLAGS
& DEBUG_SILENT
)
826 /* in release builds, be silent unless MESA_DEBUG is set */
827 debug
= _mesa_getenv("MESA_DEBUG") != NULL
;
831 /* Now only print the string if we're required to do so. */
833 fprintf(fout
, "%s: %s", prefixString
, outputString
);
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 */
843 _mesa_snprintf(buf
, sizeof(buf
), "%s: %s%s", prefixString
, outputString
, newline
? "\n" : "");
844 OutputDebugStringA(buf
);
852 * Return string version of GL error code.
855 error_string( GLenum 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";
883 * When a new type of error is recorded, print a message describing
884 * previous errors which were accumulated.
887 flush_delayed_errors( struct gl_context
*ctx
)
891 if (ctx
->ErrorDebugCount
) {
892 _mesa_snprintf(s
, MAXSTRING
, "%d similar %s errors",
893 ctx
->ErrorDebugCount
,
894 error_string(ctx
->ErrorValue
));
896 output_if_debug("Mesa", s
, GL_TRUE
);
898 ctx
->ErrorDebugCount
= 0;
904 * Report a warning (a recoverable error condition) to stderr if
905 * either DEBUG is defined or the MESA_DEBUG env var is set.
907 * \param ctx GL context.
908 * \param fmtString printf()-like format string.
911 _mesa_warning( struct gl_context
*ctx
, const char *fmtString
, ... )
915 va_start( args
, fmtString
);
916 (void) _mesa_vsnprintf( str
, MAXSTRING
, fmtString
, args
);
920 flush_delayed_errors( ctx
);
922 output_if_debug("Mesa warning", str
, GL_TRUE
);
927 * Report an internal implementation problem.
928 * Prints the message to stderr via fprintf().
930 * \param ctx GL context.
931 * \param fmtString problem description string.
934 _mesa_problem( const struct gl_context
*ctx
, const char *fmtString
, ... )
938 static int numCalls
= 0;
945 va_start( args
, fmtString
);
946 _mesa_vsnprintf( str
, MAXSTRING
, fmtString
, 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");
955 should_output(struct gl_context
*ctx
, GLenum error
, const char *fmtString
)
957 static GLint debug
= -1;
959 /* Check debug environment variable only once:
962 const char *debugEnv
= _mesa_getenv("MESA_DEBUG");
965 if (debugEnv
&& strstr(debugEnv
, "silent"))
978 if (ctx
->ErrorValue
!= error
||
979 ctx
->ErrorDebugFmtString
!= fmtString
) {
980 flush_delayed_errors( ctx
);
981 ctx
->ErrorDebugFmtString
= fmtString
;
982 ctx
->ErrorDebugCount
= 0;
985 ctx
->ErrorDebugCount
++;
992 * Record an OpenGL state error. These usually occur when the user
993 * passes invalid parameters to a GL function.
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
999 * \param ctx the GL context.
1000 * \param error the error value.
1001 * \param fmtString printf() style format string, followed by optional args
1004 _mesa_error( struct gl_context
*ctx
, GLenum error
, const char *fmtString
, ... )
1006 GLboolean do_output
, do_log
;
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
);
1012 if (do_output
|| do_log
) {
1013 char s
[MAXSTRING
], s2
[MAXSTRING
];
1017 va_start(args
, fmtString
);
1018 len
= _mesa_vsnprintf(s
, MAXSTRING
, fmtString
, args
);
1021 if (len
>= MAXSTRING
) {
1022 /* Too long error message. Whoever calls _mesa_error should use
1023 * shorter strings. */
1028 len
= _mesa_snprintf(s2
, MAXSTRING
, "%s in %s", error_string(error
), s
);
1029 if (len
>= MAXSTRING
) {
1030 /* Same as above. */
1035 /* Print the error to stderr if needed. */
1037 output_if_debug("Mesa: User error", s2
, GL_TRUE
);
1040 /* Log the error via ARB_debug_output if needed.*/
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
);
1047 /* Set the GL context error state for glGetError. */
1048 _mesa_record_error(ctx
, error
);
1053 * Report debug information. Print error message to stderr via fprintf().
1054 * No-op if DEBUG mode not enabled.
1056 * \param ctx GL context.
1057 * \param fmtString printf()-style format string, followed by optional args.
1060 _mesa_debug( const struct gl_context
*ctx
, const char *fmtString
, ... )
1065 va_start(args
, fmtString
);
1066 _mesa_vsnprintf(s
, MAXSTRING
, fmtString
, args
);
1068 output_if_debug("Mesa", s
, GL_FALSE
);
1076 * Report debug information from the shader compiler via GL_ARB_debug_output.
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.
1085 _mesa_shader_debug( struct gl_context
*ctx
, GLenum type
, GLuint id
,
1086 const char *msg
, int len
)
1088 GLenum source
= GL_DEBUG_SOURCE_SHADER_COMPILER_ARB
,
1092 case GL_DEBUG_TYPE_ERROR_ARB
:
1093 assert(id
< SHADER_ERROR_COUNT
);
1094 severity
= GL_DEBUG_SEVERITY_HIGH_ARB
;
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");
1103 _mesa_problem(ctx
, "bad enum in _mesa_shader_debug()");
1110 /* Truncate the message if necessary. */
1111 if (len
>= MAX_DEBUG_MESSAGE_LENGTH
)
1112 len
= MAX_DEBUG_MESSAGE_LENGTH
- 1;
1114 _mesa_log_msg(ctx
, source
, type
, id
, severity
, len
, msg
);