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