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