1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2016 Brian Paul, et al All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include "context.h"
29 #include "debug_output.h"
30 #include "enums.h"
31
32 #include "hash.h"
33 #include "mtypes.h"
34 #include "version.h"
35 #include "util/hash_table.h"
36 #include "util/list.h"
37 #include "util/u_memory.h"
38
39
40 static GLuint PrevDynamicID = 0;
41
42
43 /**
44 * A namespace element.
45 */
46 struct gl_debug_element
47 {
48 struct list_head link;
49
50 GLuint ID;
51 /* at which severity levels (mesa_debug_severity) is the message enabled */
52 GLbitfield State;
53 };
54
55
56 struct gl_debug_namespace
57 {
58 struct list_head Elements;
59 GLbitfield DefaultState;
60 };
61
62
63 struct gl_debug_group {
64 struct gl_debug_namespace Namespaces[MESA_DEBUG_SOURCE_COUNT][MESA_DEBUG_TYPE_COUNT];
65 };
66
67
68 /**
69 * An error, warning, or other piece of debug information for an application
70 * to consume via GL_ARB_debug_output/GL_KHR_debug.
71 */
72 struct gl_debug_message
73 {
74 enum mesa_debug_source source;
75 enum mesa_debug_type type;
76 GLuint id;
77 enum mesa_debug_severity severity;
78 /* length as given by the user - if message was explicitly null terminated,
79 * length can be negative */
80 GLsizei length;
81 GLcharARB *message;
82 };
83
84
85 /**
86 * Debug message log. It works like a ring buffer.
87 */
88 struct gl_debug_log {
89 struct gl_debug_message Messages[MAX_DEBUG_LOGGED_MESSAGES];
90 GLint NextMessage;
91 GLint NumMessages;
92 };
93
94
95 struct gl_debug_state
96 {
97 GLDEBUGPROC Callback;
98 const void *CallbackData;
99 GLboolean SyncOutput;
100 GLboolean DebugOutput;
101 GLboolean LogToStderr;
102
103 struct gl_debug_group *Groups[MAX_DEBUG_GROUP_STACK_DEPTH];
104 struct gl_debug_message GroupMessages[MAX_DEBUG_GROUP_STACK_DEPTH];
105 GLint CurrentGroup; // GroupStackDepth - 1
106
107 struct gl_debug_log Log;
108 };
109
110
111 static char out_of_memory[] = "Debugging error: out of memory";
112
113 static const GLenum debug_source_enums[] = {
114 GL_DEBUG_SOURCE_API,
115 GL_DEBUG_SOURCE_WINDOW_SYSTEM,
116 GL_DEBUG_SOURCE_SHADER_COMPILER,
117 GL_DEBUG_SOURCE_THIRD_PARTY,
118 GL_DEBUG_SOURCE_APPLICATION,
119 GL_DEBUG_SOURCE_OTHER,
120 };
121
122 static const GLenum debug_type_enums[] = {
123 GL_DEBUG_TYPE_ERROR,
124 GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
125 GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
126 GL_DEBUG_TYPE_PORTABILITY,
127 GL_DEBUG_TYPE_PERFORMANCE,
128 GL_DEBUG_TYPE_OTHER,
129 GL_DEBUG_TYPE_MARKER,
130 GL_DEBUG_TYPE_PUSH_GROUP,
131 GL_DEBUG_TYPE_POP_GROUP,
132 };
133
134 static const GLenum debug_severity_enums[] = {
135 GL_DEBUG_SEVERITY_LOW,
136 GL_DEBUG_SEVERITY_MEDIUM,
137 GL_DEBUG_SEVERITY_HIGH,
138 GL_DEBUG_SEVERITY_NOTIFICATION,
139 };
140
141
142 static enum mesa_debug_source
gl_enum_to_debug_source(GLenum e)143 gl_enum_to_debug_source(GLenum e)
144 {
145 unsigned i;
146
147 for (i = 0; i < ARRAY_SIZE(debug_source_enums); i++) {
148 if (debug_source_enums[i] == e)
149 break;
150 }
151 return i;
152 }
153
154 static enum mesa_debug_type
gl_enum_to_debug_type(GLenum e)155 gl_enum_to_debug_type(GLenum e)
156 {
157 unsigned i;
158
159 for (i = 0; i < ARRAY_SIZE(debug_type_enums); i++) {
160 if (debug_type_enums[i] == e)
161 break;
162 }
163 return i;
164 }
165
166 static enum mesa_debug_severity
gl_enum_to_debug_severity(GLenum e)167 gl_enum_to_debug_severity(GLenum e)
168 {
169 unsigned i;
170
171 for (i = 0; i < ARRAY_SIZE(debug_severity_enums); i++) {
172 if (debug_severity_enums[i] == e)
173 break;
174 }
175 return i;
176 }
177
178
179 /**
180 * Handles generating a GL_ARB_debug_output message ID generated by the GL or
181 * GLSL compiler.
182 *
183 * The GL API has this "ID" mechanism, where the intention is to allow a
184 * client to filter in/out messages based on source, type, and ID. Of course,
185 * building a giant enum list of all debug output messages that Mesa might
186 * generate is ridiculous, so instead we have our caller pass us a pointer to
187 * static storage where the ID should get stored. This ID will be shared
188 * across all contexts for that message (which seems like a desirable
189 * property, even if it's not expected by the spec), but note that it won't be
190 * the same between executions if messages aren't generated in the same order.
191 */
192 void
_mesa_debug_get_id(GLuint * id)193 _mesa_debug_get_id(GLuint *id)
194 {
195 if (!(*id)) {
196 /* Don't update *id if we raced with some other thread. */
197 p_atomic_cmpxchg(id, 0, p_atomic_inc_return(&PrevDynamicID));
198 }
199 }
200
201 static void
debug_message_clear(struct gl_debug_message * msg)202 debug_message_clear(struct gl_debug_message *msg)
203 {
204 if (msg->message != (char*)out_of_memory)
205 free(msg->message);
206 msg->message = NULL;
207 msg->length = 0;
208 }
209
210 static void
debug_message_store(struct gl_debug_message * msg,enum mesa_debug_source source,enum mesa_debug_type type,GLuint id,enum mesa_debug_severity severity,GLsizei len,const char * buf)211 debug_message_store(struct gl_debug_message *msg,
212 enum mesa_debug_source source,
213 enum mesa_debug_type type, GLuint id,
214 enum mesa_debug_severity severity,
215 GLsizei len, const char *buf)
216 {
217 GLsizei length = len;
218
219 assert(!msg->message && !msg->length);
220
221 if (length < 0)
222 length = strlen(buf);
223
224 msg->message = malloc(length+1);
225 if (msg->message) {
226 (void) strncpy(msg->message, buf, (size_t)length);
227 msg->message[length] = '\0';
228
229 msg->length = len;
230 msg->source = source;
231 msg->type = type;
232 msg->id = id;
233 msg->severity = severity;
234 } else {
235 static GLuint oom_msg_id = 0;
236 _mesa_debug_get_id(&oom_msg_id);
237
238 /* malloc failed! */
239 msg->message = out_of_memory;
240 msg->length = -1;
241 msg->source = MESA_DEBUG_SOURCE_OTHER;
242 msg->type = MESA_DEBUG_TYPE_ERROR;
243 msg->id = oom_msg_id;
244 msg->severity = MESA_DEBUG_SEVERITY_HIGH;
245 }
246 }
247
248 static void
debug_namespace_init(struct gl_debug_namespace * ns)249 debug_namespace_init(struct gl_debug_namespace *ns)
250 {
251 list_inithead(&ns->Elements);
252
253 /* Enable all the messages with severity HIGH or MEDIUM by default */
254 ns->DefaultState = (1 << MESA_DEBUG_SEVERITY_MEDIUM ) |
255 (1 << MESA_DEBUG_SEVERITY_HIGH) |
256 (1 << MESA_DEBUG_SEVERITY_NOTIFICATION);
257 }
258
259 static void
debug_namespace_clear(struct gl_debug_namespace * ns)260 debug_namespace_clear(struct gl_debug_namespace *ns)
261 {
262 list_for_each_entry_safe(struct gl_debug_element, elem, &ns->Elements, link)
263 free(elem);
264 }
265
266 static bool
debug_namespace_copy(struct gl_debug_namespace * dst,const struct gl_debug_namespace * src)267 debug_namespace_copy(struct gl_debug_namespace *dst,
268 const struct gl_debug_namespace *src)
269 {
270 dst->DefaultState = src->DefaultState;
271
272 list_inithead(&dst->Elements);
273 list_for_each_entry(struct gl_debug_element, elem, &src->Elements, link) {
274 struct gl_debug_element *copy;
275
276 copy = malloc(sizeof(*copy));
277 if (!copy) {
278 debug_namespace_clear(dst);
279 return false;
280 }
281
282 copy->ID = elem->ID;
283 copy->State = elem->State;
284 list_addtail(©->link, &dst->Elements);
285 }
286
287 return true;
288 }
289
290 /**
291 * Set the state of \p id in the namespace.
292 */
293 static bool
debug_namespace_set(struct gl_debug_namespace * ns,GLuint id,bool enabled)294 debug_namespace_set(struct gl_debug_namespace *ns,
295 GLuint id, bool enabled)
296 {
297 const uint32_t state = (enabled) ?
298 ((1 << MESA_DEBUG_SEVERITY_COUNT) - 1) : 0;
299 struct gl_debug_element *elem = NULL;
300
301 /* find the element */
302 list_for_each_entry(struct gl_debug_element, tmp, &ns->Elements, link) {
303 if (tmp->ID == id) {
304 elem = tmp;
305 break;
306 }
307 }
308
309 /* we do not need the element if it has the default state */
310 if (ns->DefaultState == state) {
311 if (elem) {
312 list_del(&elem->link);
313 free(elem);
314 }
315 return true;
316 }
317
318 if (!elem) {
319 elem = malloc(sizeof(*elem));
320 if (!elem)
321 return false;
322
323 elem->ID = id;
324 list_addtail(&elem->link, &ns->Elements);
325 }
326
327 elem->State = state;
328
329 return true;
330 }
331
332 /**
333 * Set the default state of the namespace for \p severity. When \p severity
334 * is MESA_DEBUG_SEVERITY_COUNT, the default values for all severities are
335 * updated.
336 */
337 static void
debug_namespace_set_all(struct gl_debug_namespace * ns,enum mesa_debug_severity severity,bool enabled)338 debug_namespace_set_all(struct gl_debug_namespace *ns,
339 enum mesa_debug_severity severity,
340 bool enabled)
341 {
342 uint32_t mask, val;
343
344 /* set all elements to the same state */
345 if (severity == MESA_DEBUG_SEVERITY_COUNT) {
346 ns->DefaultState = (enabled) ? ((1 << severity) - 1) : 0;
347 debug_namespace_clear(ns);
348 list_inithead(&ns->Elements);
349 return;
350 }
351
352 mask = 1 << severity;
353 val = (enabled) ? mask : 0;
354
355 ns->DefaultState = (ns->DefaultState & ~mask) | val;
356
357 list_for_each_entry_safe(struct gl_debug_element, elem, &ns->Elements,
358 link) {
359 elem->State = (elem->State & ~mask) | val;
360 if (elem->State == ns->DefaultState) {
361 list_del(&elem->link);
362 free(elem);
363 }
364 }
365 }
366
367 /**
368 * Get the state of \p id in the namespace.
369 */
370 static bool
debug_namespace_get(const struct gl_debug_namespace * ns,GLuint id,enum mesa_debug_severity severity)371 debug_namespace_get(const struct gl_debug_namespace *ns, GLuint id,
372 enum mesa_debug_severity severity)
373 {
374 uint32_t state;
375
376 state = ns->DefaultState;
377 list_for_each_entry(struct gl_debug_element, elem, &ns->Elements, link) {
378 if (elem->ID == id) {
379 state = elem->State;
380 break;
381 }
382 }
383
384 return (state & (1 << severity));
385 }
386
387 /**
388 * Allocate and initialize context debug state.
389 */
390 static struct gl_debug_state *
debug_create(void)391 debug_create(void)
392 {
393 struct gl_debug_state *debug;
394 int s, t;
395
396 debug = CALLOC_STRUCT(gl_debug_state);
397 if (!debug)
398 return NULL;
399
400 debug->Groups[0] = malloc(sizeof(*debug->Groups[0]));
401 if (!debug->Groups[0]) {
402 free(debug);
403 return NULL;
404 }
405
406 /* Initialize state for filtering known debug messages. */
407 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) {
408 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++)
409 debug_namespace_init(&debug->Groups[0]->Namespaces[s][t]);
410 }
411
412 return debug;
413 }
414
415 /**
416 * Return true if the top debug group points to the group below it.
417 */
418 static bool
debug_is_group_read_only(const struct gl_debug_state * debug)419 debug_is_group_read_only(const struct gl_debug_state *debug)
420 {
421 const GLint gstack = debug->CurrentGroup;
422 return (gstack > 0 && debug->Groups[gstack] == debug->Groups[gstack - 1]);
423 }
424
425 /**
426 * Make the top debug group writable.
427 */
428 static bool
debug_make_group_writable(struct gl_debug_state * debug)429 debug_make_group_writable(struct gl_debug_state *debug)
430 {
431 const GLint gstack = debug->CurrentGroup;
432 const struct gl_debug_group *src = debug->Groups[gstack];
433 struct gl_debug_group *dst;
434 int s, t;
435
436 if (!debug_is_group_read_only(debug))
437 return true;
438
439 dst = malloc(sizeof(*dst));
440 if (!dst)
441 return false;
442
443 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) {
444 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
445 if (!debug_namespace_copy(&dst->Namespaces[s][t],
446 &src->Namespaces[s][t])) {
447 /* error path! */
448 for (t = t - 1; t >= 0; t--)
449 debug_namespace_clear(&dst->Namespaces[s][t]);
450 for (s = s - 1; s >= 0; s--) {
451 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++)
452 debug_namespace_clear(&dst->Namespaces[s][t]);
453 }
454 free(dst);
455 return false;
456 }
457 }
458 }
459
460 debug->Groups[gstack] = dst;
461
462 return true;
463 }
464
465 /**
466 * Free the top debug group.
467 */
468 static void
debug_clear_group(struct gl_debug_state * debug)469 debug_clear_group(struct gl_debug_state *debug)
470 {
471 const GLint gstack = debug->CurrentGroup;
472
473 if (!debug_is_group_read_only(debug)) {
474 struct gl_debug_group *grp = debug->Groups[gstack];
475 int s, t;
476
477 for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++) {
478 for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++)
479 debug_namespace_clear(&grp->Namespaces[s][t]);
480 }
481
482 free(grp);
483 }
484
485 debug->Groups[gstack] = NULL;
486 }
487
488 /**
489 * Delete the oldest debug messages out of the log.
490 */
491 static void
debug_delete_messages(struct gl_debug_state * debug,int count)492 debug_delete_messages(struct gl_debug_state *debug, int count)
493 {
494 struct gl_debug_log *log = &debug->Log;
495
496 if (count > log->NumMessages)
497 count = log->NumMessages;
498
499 while (count--) {
500 struct gl_debug_message *msg = &log->Messages[log->NextMessage];
501
502 debug_message_clear(msg);
503
504 log->NumMessages--;
505 log->NextMessage++;
506 log->NextMessage %= MAX_DEBUG_LOGGED_MESSAGES;
507 }
508 }
509
510 /**
511 * Loop through debug group stack tearing down states for
512 * filtering debug messages. Then free debug output state.
513 */
514 static void
debug_destroy(struct gl_debug_state * debug)515 debug_destroy(struct gl_debug_state *debug)
516 {
517 while (debug->CurrentGroup > 0) {
518 debug_clear_group(debug);
519 debug->CurrentGroup--;
520 }
521
522 debug_clear_group(debug);
523 debug_delete_messages(debug, debug->Log.NumMessages);
524 free(debug);
525 }
526
527 /**
528 * Sets the state of the given message source/type/ID tuple.
529 */
530 static void
debug_set_message_enable(struct gl_debug_state * debug,enum mesa_debug_source source,enum mesa_debug_type type,GLuint id,GLboolean enabled)531 debug_set_message_enable(struct gl_debug_state *debug,
532 enum mesa_debug_source source,
533 enum mesa_debug_type type,
534 GLuint id, GLboolean enabled)
535 {
536 const GLint gstack = debug->CurrentGroup;
537 struct gl_debug_namespace *ns;
538
539 debug_make_group_writable(debug);
540 ns = &debug->Groups[gstack]->Namespaces[source][type];
541
542 debug_namespace_set(ns, id, enabled);
543 }
544
545 /*
546 * Set the state of all message IDs found in the given intersection of
547 * 'source', 'type', and 'severity'. The _COUNT enum can be used for
548 * GL_DONT_CARE (include all messages in the class).
549 *
550 * This requires both setting the state of all previously seen message
551 * IDs in the hash table, and setting the default state for all
552 * applicable combinations of source/type/severity, so that all the
553 * yet-unknown message IDs that may be used in the future will be
554 * impacted as if they were already known.
555 */
556 static void
debug_set_message_enable_all(struct gl_debug_state * debug,enum mesa_debug_source source,enum mesa_debug_type type,enum mesa_debug_severity severity,GLboolean enabled)557 debug_set_message_enable_all(struct gl_debug_state *debug,
558 enum mesa_debug_source source,
559 enum mesa_debug_type type,
560 enum mesa_debug_severity severity,
561 GLboolean enabled)
562 {
563 const GLint gstack = debug->CurrentGroup;
564 int s, t, smax, tmax;
565
566 if (source == MESA_DEBUG_SOURCE_COUNT) {
567 source = 0;
568 smax = MESA_DEBUG_SOURCE_COUNT;
569 } else {
570 smax = source+1;
571 }
572
573 if (type == MESA_DEBUG_TYPE_COUNT) {
574 type = 0;
575 tmax = MESA_DEBUG_TYPE_COUNT;
576 } else {
577 tmax = type+1;
578 }
579
580 debug_make_group_writable(debug);
581
582 for (s = source; s < smax; s++) {
583 for (t = type; t < tmax; t++) {
584 struct gl_debug_namespace *nspace =
585 &debug->Groups[gstack]->Namespaces[s][t];
586 debug_namespace_set_all(nspace, severity, enabled);
587 }
588 }
589 }
590
591 /**
592 * Returns if the given message source/type/ID tuple is enabled.
593 */
594 bool
_mesa_debug_is_message_enabled(const struct gl_debug_state * debug,enum mesa_debug_source source,enum mesa_debug_type type,GLuint id,enum mesa_debug_severity severity)595 _mesa_debug_is_message_enabled(const struct gl_debug_state *debug,
596 enum mesa_debug_source source,
597 enum mesa_debug_type type,
598 GLuint id,
599 enum mesa_debug_severity severity)
600 {
601 const GLint gstack = debug->CurrentGroup;
602 struct gl_debug_group *grp = debug->Groups[gstack];
603 struct gl_debug_namespace *nspace = &grp->Namespaces[source][type];
604
605 if (!debug->DebugOutput)
606 return false;
607
608 return debug_namespace_get(nspace, id, severity);
609 }
610
611 /**
612 * 'buf' is not necessarily a null-terminated string. When logging, copy
613 * 'len' characters from it, store them in a new, null-terminated string,
614 * and remember the number of bytes used by that string, *including*
615 * the null terminator this time.
616 */
617 static void
debug_log_message(struct gl_debug_state * debug,enum mesa_debug_source source,enum mesa_debug_type type,GLuint id,enum mesa_debug_severity severity,GLsizei len,const char * buf)618 debug_log_message(struct gl_debug_state *debug,
619 enum mesa_debug_source source,
620 enum mesa_debug_type type, GLuint id,
621 enum mesa_debug_severity severity,
622 GLsizei len, const char *buf)
623 {
624 struct gl_debug_log *log = &debug->Log;
625 GLint nextEmpty;
626 struct gl_debug_message *emptySlot;
627
628 if (debug->LogToStderr) {
629 _mesa_log("Mesa debug output: %.*s\n", len, buf);
630 }
631
632 assert(len < MAX_DEBUG_MESSAGE_LENGTH);
633
634 if (log->NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
635 return;
636
637 nextEmpty = (log->NextMessage + log->NumMessages)
638 % MAX_DEBUG_LOGGED_MESSAGES;
639 emptySlot = &log->Messages[nextEmpty];
640
641 debug_message_store(emptySlot, source, type,
642 id, severity, len, buf);
643
644 log->NumMessages++;
645 }
646
647 /**
648 * Return the oldest debug message out of the log.
649 */
650 static const struct gl_debug_message *
debug_fetch_message(const struct gl_debug_state * debug)651 debug_fetch_message(const struct gl_debug_state *debug)
652 {
653 const struct gl_debug_log *log = &debug->Log;
654
655 return (log->NumMessages) ? &log->Messages[log->NextMessage] : NULL;
656 }
657
658 static struct gl_debug_message *
debug_get_group_message(struct gl_debug_state * debug)659 debug_get_group_message(struct gl_debug_state *debug)
660 {
661 return &debug->GroupMessages[debug->CurrentGroup];
662 }
663
664 static void
debug_push_group(struct gl_debug_state * debug)665 debug_push_group(struct gl_debug_state *debug)
666 {
667 const GLint gstack = debug->CurrentGroup;
668
669 /* just point to the previous stack */
670 debug->Groups[gstack + 1] = debug->Groups[gstack];
671 debug->CurrentGroup++;
672 }
673
674 static void
debug_pop_group(struct gl_debug_state * debug)675 debug_pop_group(struct gl_debug_state *debug)
676 {
677 debug_clear_group(debug);
678 debug->CurrentGroup--;
679 }
680
681
682 /**
683 * Lock and return debug state for the context. The debug state will be
684 * allocated and initialized upon the first call. When NULL is returned, the
685 * debug state is not locked.
686 */
687 static struct gl_debug_state *
_mesa_lock_debug_state(struct gl_context * ctx)688 _mesa_lock_debug_state(struct gl_context *ctx)
689 {
690 simple_mtx_lock(&ctx->DebugMutex);
691
692 if (!ctx->Debug) {
693 ctx->Debug = debug_create();
694 if (!ctx->Debug) {
695 GET_CURRENT_CONTEXT(cur);
696 simple_mtx_unlock(&ctx->DebugMutex);
697
698 /*
699 * This function may be called from other threads. When that is the
700 * case, we cannot record this OOM error.
701 */
702 if (ctx == cur)
703 _mesa_error(ctx, GL_OUT_OF_MEMORY, "allocating debug state");
704
705 return NULL;
706 }
707 }
708
709 return ctx->Debug;
710 }
711
712 static void
_mesa_unlock_debug_state(struct gl_context * ctx)713 _mesa_unlock_debug_state(struct gl_context *ctx)
714 {
715 simple_mtx_unlock(&ctx->DebugMutex);
716 }
717
718 /**
719 * Set the integer debug state specified by \p pname. This can be called from
720 * _mesa_set_enable for example.
721 */
722 bool
_mesa_set_debug_state_int(struct gl_context * ctx,GLenum pname,GLint val)723 _mesa_set_debug_state_int(struct gl_context *ctx, GLenum pname, GLint val)
724 {
725 struct gl_debug_state *debug = _mesa_lock_debug_state(ctx);
726
727 if (!debug)
728 return false;
729
730 switch (pname) {
731 case GL_DEBUG_OUTPUT:
732 debug->DebugOutput = (val != 0);
733 break;
734 case GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB:
735 debug->SyncOutput = (val != 0);
736 break;
737 default:
738 assert(!"unknown debug output param");
739 break;
740 }
741
742 _mesa_unlock_debug_state(ctx);
743
744 return true;
745 }
746
747 /**
748 * Query the integer debug state specified by \p pname. This can be called
749 * _mesa_GetIntegerv for example.
750 */
751 GLint
_mesa_get_debug_state_int(struct gl_context * ctx,GLenum pname)752 _mesa_get_debug_state_int(struct gl_context *ctx, GLenum pname)
753 {
754 GLint val;
755
756 struct gl_debug_state *debug = _mesa_lock_debug_state(ctx);
757 if (!debug)
758 return 0;
759
760 switch (pname) {
761 case GL_DEBUG_OUTPUT:
762 val = debug->DebugOutput;
763 break;
764 case GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB:
765 val = debug->SyncOutput;
766 break;
767 case GL_DEBUG_LOGGED_MESSAGES:
768 val = debug->Log.NumMessages;
769 break;
770 case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH:
771 val = (debug->Log.NumMessages) ?
772 debug->Log.Messages[debug->Log.NextMessage].length + 1 : 0;
773 break;
774 case GL_DEBUG_GROUP_STACK_DEPTH:
775 val = debug->CurrentGroup + 1;
776 break;
777 default:
778 assert(!"unknown debug output param");
779 val = 0;
780 break;
781 }
782
783 _mesa_unlock_debug_state(ctx);
784
785 return val;
786 }
787
788 /**
789 * Query the pointer debug state specified by \p pname. This can be called
790 * _mesa_GetPointerv for example.
791 */
792 void *
_mesa_get_debug_state_ptr(struct gl_context * ctx,GLenum pname)793 _mesa_get_debug_state_ptr(struct gl_context *ctx, GLenum pname)
794 {
795 void *val;
796 struct gl_debug_state *debug = _mesa_lock_debug_state(ctx);
797
798 if (!debug)
799 return NULL;
800
801 switch (pname) {
802 case GL_DEBUG_CALLBACK_FUNCTION_ARB:
803 val = (void *) debug->Callback;
804 break;
805 case GL_DEBUG_CALLBACK_USER_PARAM_ARB:
806 val = (void *) debug->CallbackData;
807 break;
808 default:
809 assert(!"unknown debug output param");
810 val = NULL;
811 break;
812 }
813
814 _mesa_unlock_debug_state(ctx);
815
816 return val;
817 }
818
819 /**
820 * Insert a debug message. The mutex is assumed to be locked, and will be
821 * unlocked by this call.
822 */
823 static void
log_msg_locked_and_unlock(struct gl_context * ctx,enum mesa_debug_source source,enum mesa_debug_type type,GLuint id,enum mesa_debug_severity severity,GLint len,const char * buf)824 log_msg_locked_and_unlock(struct gl_context *ctx,
825 enum mesa_debug_source source,
826 enum mesa_debug_type type, GLuint id,
827 enum mesa_debug_severity severity,
828 GLint len, const char *buf)
829 {
830 struct gl_debug_state *debug = ctx->Debug;
831
832 if (!_mesa_debug_is_message_enabled(debug, source, type, id, severity)) {
833 _mesa_unlock_debug_state(ctx);
834 return;
835 }
836
837 if (ctx->Debug->Callback) {
838 /* Call the user's callback function */
839 GLenum gl_source = debug_source_enums[source];
840 GLenum gl_type = debug_type_enums[type];
841 GLenum gl_severity = debug_severity_enums[severity];
842 GLDEBUGPROC callback = ctx->Debug->Callback;
843 const void *data = ctx->Debug->CallbackData;
844
845 /*
846 * When ctx->Debug->SyncOutput is GL_FALSE, the client is prepared for
847 * unsynchronous calls. When it is GL_TRUE, we will not spawn threads.
848 * In either case, we can call the callback unlocked.
849 */
850 _mesa_unlock_debug_state(ctx);
851 callback(gl_source, gl_type, id, gl_severity, len, buf, data);
852 }
853 else {
854 /* add debug message to queue */
855 debug_log_message(ctx->Debug, source, type, id, severity, len, buf);
856 _mesa_unlock_debug_state(ctx);
857 }
858 }
859
860 /**
861 * Log a client or driver debug message.
862 */
863 void
_mesa_log_msg(struct gl_context * ctx,enum mesa_debug_source source,enum mesa_debug_type type,GLuint id,enum mesa_debug_severity severity,GLint len,const char * buf)864 _mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
865 enum mesa_debug_type type, GLuint id,
866 enum mesa_debug_severity severity, GLint len, const char *buf)
867 {
868 struct gl_debug_state *debug = _mesa_lock_debug_state(ctx);
869
870 if (!debug)
871 return;
872
873 log_msg_locked_and_unlock(ctx, source, type, id, severity, len, buf);
874 }
875
876
877 /**
878 * Verify that source, type, and severity are valid enums.
879 *
880 * The 'caller' param is used for handling values available
881 * only in glDebugMessageInsert or glDebugMessageControl
882 */
883 static GLboolean
validate_params(struct gl_context * ctx,unsigned caller,const char * callerstr,GLenum source,GLenum type,GLenum severity)884 validate_params(struct gl_context *ctx, unsigned caller,
885 const char *callerstr, GLenum source, GLenum type,
886 GLenum severity)
887 {
888 #define INSERT 1
889 #define CONTROL 2
890 switch(source) {
891 case GL_DEBUG_SOURCE_APPLICATION_ARB:
892 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
893 break;
894 case GL_DEBUG_SOURCE_API_ARB:
895 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
896 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
897 case GL_DEBUG_SOURCE_OTHER_ARB:
898 if (caller != INSERT)
899 break;
900 else
901 goto error;
902 case GL_DONT_CARE:
903 if (caller == CONTROL)
904 break;
905 else
906 goto error;
907 default:
908 goto error;
909 }
910
911 switch(type) {
912 case GL_DEBUG_TYPE_ERROR_ARB:
913 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
914 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
915 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
916 case GL_DEBUG_TYPE_PORTABILITY_ARB:
917 case GL_DEBUG_TYPE_OTHER_ARB:
918 case GL_DEBUG_TYPE_MARKER:
919 case GL_DEBUG_TYPE_PUSH_GROUP:
920 case GL_DEBUG_TYPE_POP_GROUP:
921 break;
922 case GL_DONT_CARE:
923 if (caller == CONTROL)
924 break;
925 else
926 goto error;
927 default:
928 goto error;
929 }
930
931 switch(severity) {
932 case GL_DEBUG_SEVERITY_HIGH_ARB:
933 case GL_DEBUG_SEVERITY_MEDIUM_ARB:
934 case GL_DEBUG_SEVERITY_LOW_ARB:
935 case GL_DEBUG_SEVERITY_NOTIFICATION:
936 break;
937 case GL_DONT_CARE:
938 if (caller == CONTROL)
939 break;
940 else
941 goto error;
942 default:
943 goto error;
944 }
945 return GL_TRUE;
946
947 error:
948 _mesa_error(ctx, GL_INVALID_ENUM, "bad values passed to %s"
949 "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
950 source, type, severity);
951
952 return GL_FALSE;
953 }
954
955
956 static GLboolean
validate_length(struct gl_context * ctx,const char * callerstr,GLsizei length,const GLchar * buf)957 validate_length(struct gl_context *ctx, const char *callerstr, GLsizei length,
958 const GLchar *buf)
959 {
960
961 if (length < 0) {
962 GLsizei len = strlen(buf);
963
964 if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
965 _mesa_error(ctx, GL_INVALID_VALUE,
966 "%s(null terminated string length=%d, is not less than "
967 "GL_MAX_DEBUG_MESSAGE_LENGTH=%d)", callerstr, len,
968 MAX_DEBUG_MESSAGE_LENGTH);
969 return GL_FALSE;
970 }
971 }
972
973 if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
974 _mesa_error(ctx, GL_INVALID_VALUE,
975 "%s(length=%d, which is not less than "
976 "GL_MAX_DEBUG_MESSAGE_LENGTH=%d)", callerstr, length,
977 MAX_DEBUG_MESSAGE_LENGTH);
978 return GL_FALSE;
979 }
980
981 return GL_TRUE;
982 }
983
984
985 void GLAPIENTRY
_mesa_DebugMessageInsert(GLenum source,GLenum type,GLuint id,GLenum severity,GLint length,const GLchar * buf)986 _mesa_DebugMessageInsert(GLenum source, GLenum type, GLuint id,
987 GLenum severity, GLint length,
988 const GLchar *buf)
989 {
990 GET_CURRENT_CONTEXT(ctx);
991 const char *callerstr;
992
993 if (_mesa_is_desktop_gl(ctx))
994 callerstr = "glDebugMessageInsert";
995 else
996 callerstr = "glDebugMessageInsertKHR";
997
998 if (!validate_params(ctx, INSERT, callerstr, source, type, severity))
999 return; /* GL_INVALID_ENUM */
1000
1001 if (!validate_length(ctx, callerstr, length, buf))
1002 return; /* GL_INVALID_VALUE */
1003
1004 /* if length not specified, string will be null terminated: */
1005 if (length < 0)
1006 length = strlen(buf);
1007
1008 _mesa_log_msg(ctx, gl_enum_to_debug_source(source),
1009 gl_enum_to_debug_type(type), id,
1010 gl_enum_to_debug_severity(severity),
1011 length, buf);
1012
1013 if (type == GL_DEBUG_TYPE_MARKER && ctx->Driver.EmitStringMarker) {
1014 ctx->Driver.EmitStringMarker(ctx, buf, length);
1015 }
1016 }
1017
1018
1019 GLuint GLAPIENTRY
_mesa_GetDebugMessageLog(GLuint count,GLsizei logSize,GLenum * sources,GLenum * types,GLenum * ids,GLenum * severities,GLsizei * lengths,GLchar * messageLog)1020 _mesa_GetDebugMessageLog(GLuint count, GLsizei logSize, GLenum *sources,
1021 GLenum *types, GLenum *ids, GLenum *severities,
1022 GLsizei *lengths, GLchar *messageLog)
1023 {
1024 GET_CURRENT_CONTEXT(ctx);
1025 struct gl_debug_state *debug;
1026 const char *callerstr;
1027 GLuint ret;
1028
1029 if (_mesa_is_desktop_gl(ctx))
1030 callerstr = "glGetDebugMessageLog";
1031 else
1032 callerstr = "glGetDebugMessageLogKHR";
1033
1034 if (!messageLog)
1035 logSize = 0;
1036
1037 if (logSize < 0) {
1038 _mesa_error(ctx, GL_INVALID_VALUE,
1039 "%s(logSize=%d : logSize must not be negative)",
1040 callerstr, logSize);
1041 return 0;
1042 }
1043
1044 debug = _mesa_lock_debug_state(ctx);
1045 if (!debug)
1046 return 0;
1047
1048 for (ret = 0; ret < count; ret++) {
1049 const struct gl_debug_message *msg = debug_fetch_message(debug);
1050 GLsizei len;
1051
1052 if (!msg)
1053 break;
1054
1055 len = msg->length;
1056 if (len < 0)
1057 len = strlen(msg->message);
1058
1059 if (logSize < len+1 && messageLog != NULL)
1060 break;
1061
1062 if (messageLog) {
1063 assert(msg->message[len] == '\0');
1064 (void) strncpy(messageLog, msg->message, (size_t)len+1);
1065
1066 messageLog += len+1;
1067 logSize -= len+1;
1068 }
1069
1070 if (lengths)
1071 *lengths++ = len+1;
1072 if (severities)
1073 *severities++ = debug_severity_enums[msg->severity];
1074 if (sources)
1075 *sources++ = debug_source_enums[msg->source];
1076 if (types)
1077 *types++ = debug_type_enums[msg->type];
1078 if (ids)
1079 *ids++ = msg->id;
1080
1081 debug_delete_messages(debug, 1);
1082 }
1083
1084 _mesa_unlock_debug_state(ctx);
1085
1086 return ret;
1087 }
1088
1089
1090 void GLAPIENTRY
_mesa_DebugMessageControl(GLenum gl_source,GLenum gl_type,GLenum gl_severity,GLsizei count,const GLuint * ids,GLboolean enabled)1091 _mesa_DebugMessageControl(GLenum gl_source, GLenum gl_type,
1092 GLenum gl_severity, GLsizei count,
1093 const GLuint *ids, GLboolean enabled)
1094 {
1095 GET_CURRENT_CONTEXT(ctx);
1096 enum mesa_debug_source source = gl_enum_to_debug_source(gl_source);
1097 enum mesa_debug_type type = gl_enum_to_debug_type(gl_type);
1098 enum mesa_debug_severity severity = gl_enum_to_debug_severity(gl_severity);
1099 const char *callerstr;
1100 struct gl_debug_state *debug;
1101
1102 if (_mesa_is_desktop_gl(ctx))
1103 callerstr = "glDebugMessageControl";
1104 else
1105 callerstr = "glDebugMessageControlKHR";
1106
1107 if (count < 0) {
1108 _mesa_error(ctx, GL_INVALID_VALUE,
1109 "%s(count=%d : count must not be negative)", callerstr,
1110 count);
1111 return;
1112 }
1113
1114 if (!validate_params(ctx, CONTROL, callerstr, gl_source, gl_type,
1115 gl_severity))
1116 return; /* GL_INVALID_ENUM */
1117
1118 if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE
1119 || gl_source == GL_DONT_CARE)) {
1120 _mesa_error(ctx, GL_INVALID_OPERATION,
1121 "%s(When passing an array of ids, severity must be"
1122 " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.",
1123 callerstr);
1124 return;
1125 }
1126
1127 debug = _mesa_lock_debug_state(ctx);
1128 if (!debug)
1129 return;
1130
1131 if (count) {
1132 GLsizei i;
1133 for (i = 0; i < count; i++)
1134 debug_set_message_enable(debug, source, type, ids[i], enabled);
1135 }
1136 else {
1137 debug_set_message_enable_all(debug, source, type, severity, enabled);
1138 }
1139
1140 _mesa_unlock_debug_state(ctx);
1141 }
1142
1143
1144 void GLAPIENTRY
_mesa_DebugMessageCallback(GLDEBUGPROC callback,const void * userParam)1145 _mesa_DebugMessageCallback(GLDEBUGPROC callback, const void *userParam)
1146 {
1147 GET_CURRENT_CONTEXT(ctx);
1148 struct gl_debug_state *debug = _mesa_lock_debug_state(ctx);
1149 if (debug) {
1150 debug->Callback = callback;
1151 debug->CallbackData = userParam;
1152 _mesa_unlock_debug_state(ctx);
1153 }
1154 }
1155
1156
1157 void GLAPIENTRY
_mesa_PushDebugGroup(GLenum source,GLuint id,GLsizei length,const GLchar * message)1158 _mesa_PushDebugGroup(GLenum source, GLuint id, GLsizei length,
1159 const GLchar *message)
1160 {
1161 GET_CURRENT_CONTEXT(ctx);
1162 const char *callerstr;
1163 struct gl_debug_state *debug;
1164 struct gl_debug_message *emptySlot;
1165
1166 if (_mesa_is_desktop_gl(ctx))
1167 callerstr = "glPushDebugGroup";
1168 else
1169 callerstr = "glPushDebugGroupKHR";
1170
1171 switch(source) {
1172 case GL_DEBUG_SOURCE_APPLICATION:
1173 case GL_DEBUG_SOURCE_THIRD_PARTY:
1174 break;
1175 default:
1176 _mesa_error(ctx, GL_INVALID_ENUM, "bad value passed to %s"
1177 "(source=0x%x)", callerstr, source);
1178 return;
1179 }
1180
1181 if (!validate_length(ctx, callerstr, length, message))
1182 return; /* GL_INVALID_VALUE */
1183
1184 if (length < 0)
1185 length = strlen(message);
1186
1187 debug = _mesa_lock_debug_state(ctx);
1188 if (!debug)
1189 return;
1190
1191 if (debug->CurrentGroup >= MAX_DEBUG_GROUP_STACK_DEPTH-1) {
1192 _mesa_unlock_debug_state(ctx);
1193 _mesa_error(ctx, GL_STACK_OVERFLOW, "%s", callerstr);
1194 return;
1195 }
1196
1197 /* pop reuses the message details from push so we store this */
1198 emptySlot = debug_get_group_message(debug);
1199 debug_message_store(emptySlot,
1200 gl_enum_to_debug_source(source),
1201 gl_enum_to_debug_type(GL_DEBUG_TYPE_PUSH_GROUP),
1202 id,
1203 gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
1204 length, message);
1205
1206 debug_push_group(debug);
1207
1208 log_msg_locked_and_unlock(ctx,
1209 gl_enum_to_debug_source(source),
1210 MESA_DEBUG_TYPE_PUSH_GROUP, id,
1211 MESA_DEBUG_SEVERITY_NOTIFICATION, length,
1212 message);
1213 }
1214
1215
1216 void GLAPIENTRY
_mesa_PopDebugGroup(void)1217 _mesa_PopDebugGroup(void)
1218 {
1219 GET_CURRENT_CONTEXT(ctx);
1220 const char *callerstr;
1221 struct gl_debug_state *debug;
1222 struct gl_debug_message *gdmessage, msg;
1223
1224 if (_mesa_is_desktop_gl(ctx))
1225 callerstr = "glPopDebugGroup";
1226 else
1227 callerstr = "glPopDebugGroupKHR";
1228
1229 debug = _mesa_lock_debug_state(ctx);
1230 if (!debug)
1231 return;
1232
1233 if (debug->CurrentGroup <= 0) {
1234 _mesa_unlock_debug_state(ctx);
1235 _mesa_error(ctx, GL_STACK_UNDERFLOW, "%s", callerstr);
1236 return;
1237 }
1238
1239 debug_pop_group(debug);
1240
1241 /* make a shallow copy */
1242 gdmessage = debug_get_group_message(debug);
1243 msg = *gdmessage;
1244 gdmessage->message = NULL;
1245 gdmessage->length = 0;
1246
1247 log_msg_locked_and_unlock(ctx,
1248 msg.source,
1249 gl_enum_to_debug_type(GL_DEBUG_TYPE_POP_GROUP),
1250 msg.id,
1251 gl_enum_to_debug_severity(GL_DEBUG_SEVERITY_NOTIFICATION),
1252 msg.length, msg.message);
1253
1254 debug_message_clear(&msg);
1255 }
1256
1257
1258 void
_mesa_init_debug_output(struct gl_context * ctx)1259 _mesa_init_debug_output(struct gl_context *ctx)
1260 {
1261 simple_mtx_init(&ctx->DebugMutex, mtx_plain);
1262
1263 if (MESA_DEBUG_FLAGS & DEBUG_CONTEXT) {
1264 /* If the MESA_DEBUG env is set to "context", we'll turn on the
1265 * GL_CONTEXT_FLAG_DEBUG_BIT context flag and log debug output
1266 * messages to stderr (or whatever MESA_LOG_FILE points at).
1267 */
1268 struct gl_debug_state *debug = _mesa_lock_debug_state(ctx);
1269 if (!debug) {
1270 return;
1271 }
1272 debug->DebugOutput = GL_TRUE;
1273 debug->LogToStderr = GL_TRUE;
1274 ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_DEBUG_BIT;
1275 _mesa_unlock_debug_state(ctx);
1276 }
1277 }
1278
1279
1280 void
_mesa_destroy_debug_output(struct gl_context * ctx)1281 _mesa_destroy_debug_output(struct gl_context *ctx)
1282 {
1283 if (ctx->Debug) {
1284 debug_destroy(ctx->Debug);
1285 /* set to NULL just in case it is used before context is completely gone. */
1286 ctx->Debug = NULL;
1287 }
1288
1289 simple_mtx_destroy(&ctx->DebugMutex);
1290 }
1291
1292 void GLAPIENTRY
_mesa_StringMarkerGREMEDY(GLsizei len,const GLvoid * string)1293 _mesa_StringMarkerGREMEDY(GLsizei len, const GLvoid *string)
1294 {
1295 GET_CURRENT_CONTEXT(ctx);
1296 if (ctx->Extensions.GREMEDY_string_marker) {
1297 /* if length not specified, string will be null terminated: */
1298 if (len <= 0)
1299 len = strlen(string);
1300 ctx->Driver.EmitStringMarker(ctx, string, len);
1301 } else {
1302 _mesa_error(ctx, GL_INVALID_OPERATION, "StringMarkerGREMEDY");
1303 }
1304 }
1305