errors.c revision e59fc3faa504fe56a3b2702bf49a70d392faac57
1/**
2 * \file errors.c
3 * Mesa debugging and error handling functions.
4 */
5
6/*
7 * Mesa 3-D graphics library
8 * Version:  7.1
9 *
10 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30
31#include "errors.h"
32#include "enums.h"
33#include "imports.h"
34#include "context.h"
35#include "dispatch.h"
36#include "hash.h"
37#include "mtypes.h"
38#include "version.h"
39#include "hash_table.h"
40#include "glapi/glthread.h"
41
42_glthread_DECLARE_STATIC_MUTEX(DynamicIDMutex);
43static GLuint NextDynamicID = 1;
44
45struct gl_debug_severity
46{
47   struct simple_node link;
48   GLuint ID;
49};
50
51static char out_of_memory[] = "Debugging error: out of memory";
52
53static const GLenum debug_source_enums[] = {
54   GL_DEBUG_SOURCE_API,
55   GL_DEBUG_SOURCE_WINDOW_SYSTEM,
56   GL_DEBUG_SOURCE_SHADER_COMPILER,
57   GL_DEBUG_SOURCE_THIRD_PARTY,
58   GL_DEBUG_SOURCE_APPLICATION,
59   GL_DEBUG_SOURCE_OTHER,
60};
61
62static const GLenum debug_type_enums[] = {
63   GL_DEBUG_TYPE_ERROR,
64   GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
65   GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
66   GL_DEBUG_TYPE_PORTABILITY,
67   GL_DEBUG_TYPE_PERFORMANCE,
68   GL_DEBUG_TYPE_OTHER,
69};
70
71static const GLenum debug_severity_enums[] = {
72   GL_DEBUG_SEVERITY_LOW,
73   GL_DEBUG_SEVERITY_MEDIUM,
74   GL_DEBUG_SEVERITY_HIGH,
75};
76
77static enum mesa_debug_source
78gl_enum_to_debug_source(GLenum e)
79{
80   int i;
81
82   for (i = 0; i < Elements(debug_source_enums); i++) {
83      if (debug_source_enums[i] == e)
84         break;
85   }
86   return i;
87}
88
89static enum mesa_debug_type
90gl_enum_to_debug_type(GLenum e)
91{
92   int i;
93
94   for (i = 0; i < Elements(debug_type_enums); i++) {
95      if (debug_type_enums[i] == e)
96         break;
97   }
98   return i;
99}
100
101static enum mesa_debug_severity
102gl_enum_to_debug_severity(GLenum e)
103{
104   int i;
105
106   for (i = 0; i < Elements(debug_severity_enums); i++) {
107      if (debug_severity_enums[i] == e)
108         break;
109   }
110   return i;
111}
112
113/**
114 * Handles generating a GL_ARB_debug_output message ID generated by the GL or
115 * GLSL compiler.
116 *
117 * The GL API has this "ID" mechanism, where the intention is to allow a
118 * client to filter in/out messages based on source, type, and ID.  Of course,
119 * building a giant enum list of all debug output messages that Mesa might
120 * generate is ridiculous, so instead we have our caller pass us a pointer to
121 * static storage where the ID should get stored.  This ID will be shared
122 * across all contexts for that message (which seems like a desirable
123 * property, even if it's not expected by the spec), but note that it won't be
124 * the same between executions if messages aren't generated in the same order.
125 */
126static void
127debug_get_id(GLuint *id)
128{
129   if (!(*id)) {
130      _glthread_LOCK_MUTEX(DynamicIDMutex);
131      if (!(*id))
132         *id = NextDynamicID++;
133      _glthread_UNLOCK_MUTEX(DynamicIDMutex);
134   }
135}
136
137/*
138 * We store a bitfield in the hash table, with five possible values total.
139 *
140 * The ENABLED_BIT's purpose is self-explanatory.
141 *
142 * The FOUND_BIT is needed to differentiate the value of DISABLED from
143 * the value returned by HashTableLookup() when it can't find the given key.
144 *
145 * The KNOWN_SEVERITY bit is a bit complicated:
146 *
147 * A client may call Control() with an array of IDs, then call Control()
148 * on all message IDs of a certain severity, then Insert() one of the
149 * previously specified IDs, giving us a known severity level, then call
150 * Control() on all message IDs of a certain severity level again.
151 *
152 * After the first call, those IDs will have a FOUND_BIT, but will not
153 * exist in any severity-specific list, so the second call will not
154 * impact them. This is undesirable but unavoidable given the API:
155 * The only entrypoint that gives a severity for a client-defined ID
156 * is the Insert() call.
157 *
158 * For the sake of Control(), we want to maintain the invariant
159 * that an ID will either appear in none of the three severity lists,
160 * or appear once, to minimize pointless duplication and potential surprises.
161 *
162 * Because Insert() is the only place that will learn an ID's severity,
163 * it should insert an ID into the appropriate list, but only if the ID
164 * doesn't exist in it or any other list yet. Because searching all three
165 * lists at O(n) is needlessly expensive, we store KNOWN_SEVERITY.
166 */
167enum {
168   FOUND_BIT = 1 << 0,
169   ENABLED_BIT = 1 << 1,
170   KNOWN_SEVERITY = 1 << 2,
171
172   /* HashTable reserves zero as a return value meaning 'not found' */
173   NOT_FOUND = 0,
174   DISABLED = FOUND_BIT,
175   ENABLED = ENABLED_BIT | FOUND_BIT
176};
177
178/**
179 * Returns the state of the given message source/type/ID tuple.
180 */
181static GLboolean
182should_log(struct gl_context *ctx,
183           enum mesa_debug_source source,
184           enum mesa_debug_type type,
185           GLuint id,
186           enum mesa_debug_severity severity)
187{
188   struct gl_debug_namespace *nspace =
189         &ctx->Debug.Namespaces[source][type];
190   uintptr_t state;
191
192   /* In addition to not being able to store zero as a value, HashTable also
193      can't use zero as a key. */
194   if (id)
195      state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
196   else
197      state = nspace->ZeroID;
198
199   /* Only do this once for each ID. This makes sure the ID exists in,
200      at most, one list, and does not pointlessly appear multiple times. */
201   if (!(state & KNOWN_SEVERITY)) {
202      struct gl_debug_severity *entry;
203
204      if (state == NOT_FOUND) {
205         if (ctx->Debug.Defaults[severity][source][type])
206            state = ENABLED;
207         else
208            state = DISABLED;
209      }
210
211      entry = malloc(sizeof *entry);
212      if (!entry)
213         goto out;
214
215      state |= KNOWN_SEVERITY;
216
217      if (id)
218         _mesa_HashInsert(nspace->IDs, id, (void*)state);
219      else
220         nspace->ZeroID = state;
221
222      entry->ID = id;
223      insert_at_tail(&nspace->Severity[severity], &entry->link);
224   }
225
226out:
227   return !!(state & ENABLED_BIT);
228}
229
230/**
231 * Sets the state of the given message source/type/ID tuple.
232 */
233static void
234set_message_state(struct gl_context *ctx,
235                  enum mesa_debug_source source,
236                  enum mesa_debug_type type,
237                  GLuint id, GLboolean enabled)
238{
239   struct gl_debug_namespace *nspace =
240         &ctx->Debug.Namespaces[source][type];
241   uintptr_t state;
242
243   /* In addition to not being able to store zero as a value, HashTable also
244      can't use zero as a key. */
245   if (id)
246      state = (uintptr_t)_mesa_HashLookup(nspace->IDs, id);
247   else
248      state = nspace->ZeroID;
249
250   if (state == NOT_FOUND)
251      state = enabled ? ENABLED : DISABLED;
252   else {
253      if (enabled)
254         state |= ENABLED_BIT;
255      else
256         state &= ~ENABLED_BIT;
257   }
258
259   if (id)
260      _mesa_HashInsert(nspace->IDs, id, (void*)state);
261   else
262      nspace->ZeroID = state;
263}
264
265/**
266 * 'buf' is not necessarily a null-terminated string. When logging, copy
267 * 'len' characters from it, store them in a new, null-terminated string,
268 * and remember the number of bytes used by that string, *including*
269 * the null terminator this time.
270 */
271static void
272_mesa_log_msg(struct gl_context *ctx, enum mesa_debug_source source,
273              enum mesa_debug_type type, GLuint id,
274              enum mesa_debug_severity severity, GLint len, const char *buf)
275{
276   GLint nextEmpty;
277   struct gl_debug_msg *emptySlot;
278
279   assert(len >= 0 && len < MAX_DEBUG_MESSAGE_LENGTH);
280
281   if (!should_log(ctx, source, type, id, severity))
282      return;
283
284   if (ctx->Debug.Callback) {
285      ctx->Debug.Callback(debug_source_enums[source],
286                          debug_type_enums[type],
287                          id,
288                          debug_severity_enums[severity],
289                          len, buf, ctx->Debug.CallbackData);
290      return;
291   }
292
293   if (ctx->Debug.NumMessages == MAX_DEBUG_LOGGED_MESSAGES)
294      return;
295
296   nextEmpty = (ctx->Debug.NextMsg + ctx->Debug.NumMessages)
297                          % MAX_DEBUG_LOGGED_MESSAGES;
298   emptySlot = &ctx->Debug.Log[nextEmpty];
299
300   assert(!emptySlot->message && !emptySlot->length);
301
302   emptySlot->message = malloc(len+1);
303   if (emptySlot->message) {
304      (void) strncpy(emptySlot->message, buf, (size_t)len);
305      emptySlot->message[len] = '\0';
306
307      emptySlot->length = len+1;
308      emptySlot->source = source;
309      emptySlot->type = type;
310      emptySlot->id = id;
311      emptySlot->severity = severity;
312   } else {
313      static GLuint oom_msg_id = 0;
314      debug_get_id(&oom_msg_id);
315
316      /* malloc failed! */
317      emptySlot->message = out_of_memory;
318      emptySlot->length = strlen(out_of_memory)+1;
319      emptySlot->source = MESA_DEBUG_SOURCE_OTHER;
320      emptySlot->type = MESA_DEBUG_TYPE_ERROR;
321      emptySlot->id = oom_msg_id;
322      emptySlot->severity = MESA_DEBUG_SEVERITY_HIGH;
323   }
324
325   if (ctx->Debug.NumMessages == 0)
326      ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
327
328   ctx->Debug.NumMessages++;
329}
330
331/**
332 * Pop the oldest debug message out of the log.
333 * Writes the message string, including the null terminator, into 'buf',
334 * using up to 'bufSize' bytes. If 'bufSize' is too small, or
335 * if 'buf' is NULL, nothing is written.
336 *
337 * Returns the number of bytes written on success, or when 'buf' is NULL,
338 * the number that would have been written. A return value of 0
339 * indicates failure.
340 */
341static GLsizei
342_mesa_get_msg(struct gl_context *ctx, GLenum *source, GLenum *type,
343              GLuint *id, GLenum *severity, GLsizei bufSize, char *buf)
344{
345   struct gl_debug_msg *msg;
346   GLsizei length;
347
348   if (ctx->Debug.NumMessages == 0)
349      return 0;
350
351   msg = &ctx->Debug.Log[ctx->Debug.NextMsg];
352   length = msg->length;
353
354   assert(length > 0 && length == ctx->Debug.NextMsgLength);
355
356   if (bufSize < length && buf != NULL)
357      return 0;
358
359   if (severity)
360      *severity = debug_severity_enums[msg->severity];
361   if (source)
362      *source = debug_source_enums[msg->source];
363   if (type)
364      *type = debug_type_enums[msg->type];
365   if (id)
366      *id = msg->id;
367
368   if (buf) {
369      assert(msg->message[length-1] == '\0');
370      (void) strncpy(buf, msg->message, (size_t)length);
371   }
372
373   if (msg->message != (char*)out_of_memory)
374      free(msg->message);
375   msg->message = NULL;
376   msg->length = 0;
377
378   ctx->Debug.NumMessages--;
379   ctx->Debug.NextMsg++;
380   ctx->Debug.NextMsg %= MAX_DEBUG_LOGGED_MESSAGES;
381   ctx->Debug.NextMsgLength = ctx->Debug.Log[ctx->Debug.NextMsg].length;
382
383   return length;
384}
385
386/**
387 * Verify that source, type, and severity are valid enums.
388 * glDebugMessageInsertARB only accepts two values for 'source',
389 * and glDebugMessageControlARB will additionally accept GL_DONT_CARE
390 * in any parameter, so handle those cases specially.
391 */
392static GLboolean
393validate_params(struct gl_context *ctx, unsigned caller,
394                GLenum source, GLenum type, GLenum severity)
395{
396#define INSERT 1
397#define CONTROL 2
398   switch(source) {
399   case GL_DEBUG_SOURCE_APPLICATION_ARB:
400   case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
401      break;
402   case GL_DEBUG_SOURCE_API_ARB:
403   case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
404   case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
405   case GL_DEBUG_SOURCE_OTHER_ARB:
406      if (caller != INSERT)
407         break;
408   case GL_DONT_CARE:
409      if (caller == CONTROL)
410         break;
411   default:
412      goto error;
413   }
414
415   switch(type) {
416   case GL_DEBUG_TYPE_ERROR_ARB:
417   case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
418   case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
419   case GL_DEBUG_TYPE_PERFORMANCE_ARB:
420   case GL_DEBUG_TYPE_PORTABILITY_ARB:
421   case GL_DEBUG_TYPE_OTHER_ARB:
422      break;
423   case GL_DONT_CARE:
424      if (caller == CONTROL)
425         break;
426   default:
427      goto error;
428   }
429
430   switch(severity) {
431   case GL_DEBUG_SEVERITY_HIGH_ARB:
432   case GL_DEBUG_SEVERITY_MEDIUM_ARB:
433   case GL_DEBUG_SEVERITY_LOW_ARB:
434      break;
435   case GL_DONT_CARE:
436      if (caller == CONTROL)
437         break;
438   default:
439      goto error;
440   }
441   return GL_TRUE;
442
443error:
444   {
445      const char *callerstr;
446      if (caller == INSERT)
447         callerstr = "glDebugMessageInsertARB";
448      else if (caller == CONTROL)
449         callerstr = "glDebugMessageControlARB";
450      else
451         return GL_FALSE;
452
453      _mesa_error( ctx, GL_INVALID_ENUM, "bad values passed to %s"
454                  "(source=0x%x, type=0x%x, severity=0x%x)", callerstr,
455                  source, type, severity);
456   }
457   return GL_FALSE;
458}
459
460void GLAPIENTRY
461_mesa_DebugMessageInsertARB(GLenum source, GLenum type, GLuint id,
462                            GLenum severity, GLint length,
463                            const GLcharARB* buf)
464{
465   GET_CURRENT_CONTEXT(ctx);
466
467   if (!validate_params(ctx, INSERT, source, type, severity))
468      return; /* GL_INVALID_ENUM */
469
470   if (length < 0)
471      length = strlen(buf);
472
473   if (length >= MAX_DEBUG_MESSAGE_LENGTH) {
474      _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageInsertARB"
475                 "(length=%d, which is not less than "
476                 "GL_MAX_DEBUG_MESSAGE_LENGTH_ARB=%d)", length,
477                 MAX_DEBUG_MESSAGE_LENGTH);
478      return;
479   }
480
481   _mesa_log_msg(ctx,
482                 gl_enum_to_debug_source(source),
483                 gl_enum_to_debug_type(type), id,
484                 gl_enum_to_debug_severity(severity), length, buf);
485}
486
487GLuint GLAPIENTRY
488_mesa_GetDebugMessageLogARB(GLuint count, GLsizei logSize, GLenum* sources,
489                            GLenum* types, GLenum* ids, GLenum* severities,
490                            GLsizei* lengths, GLcharARB* messageLog)
491{
492   GET_CURRENT_CONTEXT(ctx);
493   GLuint ret;
494
495   if (!messageLog)
496      logSize = 0;
497
498   if (logSize < 0) {
499      _mesa_error(ctx, GL_INVALID_VALUE, "glGetDebugMessageLogARB"
500                 "(logSize=%d : logSize must not be negative)", logSize);
501      return 0;
502   }
503
504   for (ret = 0; ret < count; ret++) {
505      GLsizei written = _mesa_get_msg(ctx, sources, types, ids, severities,
506                                      logSize, messageLog);
507      if (!written)
508         break;
509
510      if (messageLog) {
511         messageLog += written;
512         logSize -= written;
513      }
514      if (lengths) {
515         *lengths = written;
516         lengths++;
517      }
518
519      if (severities)
520         severities++;
521      if (sources)
522         sources++;
523      if (types)
524         types++;
525      if (ids)
526         ids++;
527   }
528
529   return ret;
530}
531
532/**
533 * Set the state of all message IDs found in the given intersection of
534 * 'source', 'type', and 'severity'.  The _COUNT enum can be used for
535 * GL_DONT_CARE (include all messages in the class).
536 *
537 * This requires both setting the state of all previously seen message
538 * IDs in the hash table, and setting the default state for all
539 * applicable combinations of source/type/severity, so that all the
540 * yet-unknown message IDs that may be used in the future will be
541 * impacted as if they were already known.
542 */
543static void
544control_messages(struct gl_context *ctx,
545                 enum mesa_debug_source source,
546                 enum mesa_debug_type type,
547                 enum mesa_debug_severity severity,
548                 GLboolean enabled)
549{
550   int s, t, sev, smax, tmax, sevmax;
551
552   if (source == MESA_DEBUG_SOURCE_COUNT) {
553      source = 0;
554      smax = MESA_DEBUG_SOURCE_COUNT;
555   } else {
556      smax = source+1;
557   }
558
559   if (type == MESA_DEBUG_TYPE_COUNT) {
560      type = 0;
561      tmax = MESA_DEBUG_TYPE_COUNT;
562   } else {
563      tmax = type+1;
564   }
565
566   if (severity == MESA_DEBUG_SEVERITY_COUNT) {
567      severity = 0;
568      sevmax = MESA_DEBUG_SEVERITY_COUNT;
569   } else {
570      sevmax = severity+1;
571   }
572
573   for (sev = severity; sev < sevmax; sev++)
574      for (s = source; s < smax; s++)
575         for (t = type; t < tmax; t++) {
576            struct simple_node *node;
577            struct gl_debug_severity *entry;
578
579            /* change the default for IDs we've never seen before. */
580            ctx->Debug.Defaults[sev][s][t] = enabled;
581
582            /* Now change the state of IDs we *have* seen... */
583            foreach(node, &ctx->Debug.Namespaces[s][t].Severity[sev]) {
584               entry = (struct gl_debug_severity *)node;
585               set_message_state(ctx, s, t, entry->ID, enabled);
586            }
587         }
588}
589
590/**
591 * Debugging-message namespaces with the source APPLICATION or THIRD_PARTY
592 * require special handling, since the IDs in them are controlled by clients,
593 * not the OpenGL implementation.
594 *
595 * 'count' is the length of the array 'ids'. If 'count' is nonzero, all
596 * the given IDs in the namespace defined by 'esource' and 'etype'
597 * will be affected.
598 *
599 * If 'count' is zero, this sets the state of all IDs that match
600 * the combination of 'esource', 'etype', and 'eseverity'.
601 */
602static void
603control_app_messages(struct gl_context *ctx, GLenum esource, GLenum etype,
604                     GLenum eseverity, GLsizei count, const GLuint *ids,
605                     GLboolean enabled)
606{
607   GLsizei i;
608   enum mesa_debug_source source = gl_enum_to_debug_source(esource);
609   enum mesa_debug_type type = gl_enum_to_debug_type(etype);
610   enum mesa_debug_severity severity = gl_enum_to_debug_severity(eseverity);
611
612   if (count)
613      assert(severity == MESA_DEBUG_SEVERITY_COUNT
614             && type != MESA_DEBUG_TYPE_COUNT
615             && source != MESA_DEBUG_SOURCE_COUNT);
616
617   for (i = 0; i < count; i++)
618      set_message_state(ctx, source, type, ids[i], enabled);
619
620   if (count)
621      return;
622
623   control_messages(ctx, source, type, severity, enabled);
624}
625
626void GLAPIENTRY
627_mesa_DebugMessageControlARB(GLenum gl_source, GLenum gl_type,
628                             GLenum gl_severity,
629                             GLsizei count, const GLuint *ids,
630                             GLboolean enabled)
631{
632   enum mesa_debug_source source;
633   enum mesa_debug_type type;
634   enum mesa_debug_severity severity;
635   GET_CURRENT_CONTEXT(ctx);
636
637   if (count < 0) {
638      _mesa_error(ctx, GL_INVALID_VALUE, "glDebugMessageControlARB"
639                 "(count=%d : count must not be negative)", count);
640      return;
641   }
642
643   if (!validate_params(ctx, CONTROL, gl_source, gl_type, gl_severity))
644      return; /* GL_INVALID_ENUM */
645
646   if (count && (gl_severity != GL_DONT_CARE || gl_type == GL_DONT_CARE
647                 || gl_source == GL_DONT_CARE)) {
648      _mesa_error(ctx, GL_INVALID_OPERATION, "glDebugMessageControlARB"
649                 "(When passing an array of ids, severity must be"
650         " GL_DONT_CARE, and source and type must not be GL_DONT_CARE.");
651      return;
652   }
653
654   source = gl_enum_to_debug_source(gl_source);
655   type = gl_enum_to_debug_type(gl_type);
656   severity = gl_enum_to_debug_severity(gl_severity);
657
658   control_app_messages(ctx, source, type, severity, count, ids, enabled);
659}
660
661void GLAPIENTRY
662_mesa_DebugMessageCallbackARB(GLDEBUGPROCARB callback, const GLvoid *userParam)
663{
664   GET_CURRENT_CONTEXT(ctx);
665   ctx->Debug.Callback = callback;
666   ctx->Debug.CallbackData = (void *) userParam;
667}
668
669void
670_mesa_init_errors(struct gl_context *ctx)
671{
672   int s, t, sev;
673
674   ctx->Debug.Callback = NULL;
675   ctx->Debug.SyncOutput = GL_FALSE;
676   ctx->Debug.Log[0].length = 0;
677   ctx->Debug.NumMessages = 0;
678   ctx->Debug.NextMsg = 0;
679   ctx->Debug.NextMsgLength = 0;
680
681   /* Enable all the messages with severity HIGH or MEDIUM by default. */
682   memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH], GL_TRUE,
683          sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_HIGH]);
684   memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM], GL_TRUE,
685          sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_MEDIUM]);
686   memset(ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW], GL_FALSE,
687          sizeof ctx->Debug.Defaults[MESA_DEBUG_SEVERITY_LOW]);
688
689   /* Initialize state for filtering known debug messages. */
690   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
691      for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
692         ctx->Debug.Namespaces[s][t].IDs = _mesa_NewHashTable();
693         assert(ctx->Debug.Namespaces[s][t].IDs);
694
695         for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++)
696            make_empty_list(&ctx->Debug.Namespaces[s][t].Severity[sev]);
697      }
698}
699
700static void
701do_nothing(GLuint key, void *data, void *userData)
702{
703}
704
705void
706_mesa_free_errors_data(struct gl_context *ctx)
707{
708   enum mesa_debug_type t;
709   enum mesa_debug_source s;
710   enum mesa_debug_severity sev;
711
712   /* Tear down state for filtering debug messages. */
713   for (s = 0; s < MESA_DEBUG_SOURCE_COUNT; s++)
714      for (t = 0; t < MESA_DEBUG_TYPE_COUNT; t++) {
715         _mesa_HashDeleteAll(ctx->Debug.Namespaces[s][t].IDs, do_nothing, NULL);
716         _mesa_DeleteHashTable(ctx->Debug.Namespaces[s][t].IDs);
717         for (sev = 0; sev < MESA_DEBUG_SEVERITY_COUNT; sev++) {
718            struct simple_node *node, *tmp;
719            struct gl_debug_severity *entry;
720
721            foreach_s(node, tmp, &ctx->Debug.Namespaces[s][t].Severity[sev]) {
722               entry = (struct gl_debug_severity *)node;
723               free(entry);
724            }
725         }
726      }
727}
728
729/**********************************************************************/
730/** \name Diagnostics */
731/*@{*/
732
733static void
734output_if_debug(const char *prefixString, const char *outputString,
735                GLboolean newline)
736{
737   static int debug = -1;
738   static FILE *fout = NULL;
739
740   /* Init the local 'debug' var once.
741    * Note: the _mesa_init_debug() function should have been called
742    * by now so MESA_DEBUG_FLAGS will be initialized.
743    */
744   if (debug == -1) {
745      /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
746       * etc to the named file.  Otherwise, output to stderr.
747       */
748      const char *logFile = _mesa_getenv("MESA_LOG_FILE");
749      if (logFile)
750         fout = fopen(logFile, "w");
751      if (!fout)
752         fout = stderr;
753#ifdef DEBUG
754      /* in debug builds, print messages unless MESA_DEBUG="silent" */
755      if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
756         debug = 0;
757      else
758         debug = 1;
759#else
760      /* in release builds, be silent unless MESA_DEBUG is set */
761      debug = _mesa_getenv("MESA_DEBUG") != NULL;
762#endif
763   }
764
765   /* Now only print the string if we're required to do so. */
766   if (debug) {
767      fprintf(fout, "%s: %s", prefixString, outputString);
768      if (newline)
769         fprintf(fout, "\n");
770      fflush(fout);
771
772#if defined(_WIN32) && !defined(_WIN32_WCE)
773      /* stderr from windows applications without console is not usually
774       * visible, so communicate with the debugger instead */
775      {
776         char buf[4096];
777         _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
778         OutputDebugStringA(buf);
779      }
780#endif
781   }
782}
783
784/**
785 * When a new type of error is recorded, print a message describing
786 * previous errors which were accumulated.
787 */
788static void
789flush_delayed_errors( struct gl_context *ctx )
790{
791   char s[MAX_DEBUG_MESSAGE_LENGTH];
792
793   if (ctx->ErrorDebugCount) {
794      _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
795                     ctx->ErrorDebugCount,
796                     _mesa_lookup_enum_by_nr(ctx->ErrorValue));
797
798      output_if_debug("Mesa", s, GL_TRUE);
799
800      ctx->ErrorDebugCount = 0;
801   }
802}
803
804
805/**
806 * Report a warning (a recoverable error condition) to stderr if
807 * either DEBUG is defined or the MESA_DEBUG env var is set.
808 *
809 * \param ctx GL context.
810 * \param fmtString printf()-like format string.
811 */
812void
813_mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
814{
815   char str[MAX_DEBUG_MESSAGE_LENGTH];
816   va_list args;
817   va_start( args, fmtString );
818   (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
819   va_end( args );
820
821   if (ctx)
822      flush_delayed_errors( ctx );
823
824   output_if_debug("Mesa warning", str, GL_TRUE);
825}
826
827
828/**
829 * Report an internal implementation problem.
830 * Prints the message to stderr via fprintf().
831 *
832 * \param ctx GL context.
833 * \param fmtString problem description string.
834 */
835void
836_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
837{
838   va_list args;
839   char str[MAX_DEBUG_MESSAGE_LENGTH];
840   static int numCalls = 0;
841
842   (void) ctx;
843
844   if (numCalls < 50) {
845      numCalls++;
846
847      va_start( args, fmtString );
848      _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
849      va_end( args );
850      fprintf(stderr, "Mesa %s implementation error: %s\n",
851              PACKAGE_VERSION, str);
852      fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
853   }
854}
855
856static GLboolean
857should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
858{
859   static GLint debug = -1;
860
861   /* Check debug environment variable only once:
862    */
863   if (debug == -1) {
864      const char *debugEnv = _mesa_getenv("MESA_DEBUG");
865
866#ifdef DEBUG
867      if (debugEnv && strstr(debugEnv, "silent"))
868         debug = GL_FALSE;
869      else
870         debug = GL_TRUE;
871#else
872      if (debugEnv)
873         debug = GL_TRUE;
874      else
875         debug = GL_FALSE;
876#endif
877   }
878
879   if (debug) {
880      if (ctx->ErrorValue != error ||
881          ctx->ErrorDebugFmtString != fmtString) {
882         flush_delayed_errors( ctx );
883         ctx->ErrorDebugFmtString = fmtString;
884         ctx->ErrorDebugCount = 0;
885         return GL_TRUE;
886      }
887      ctx->ErrorDebugCount++;
888   }
889   return GL_FALSE;
890}
891
892void
893_mesa_gl_debug(struct gl_context *ctx,
894               GLuint *id,
895               enum mesa_debug_type type,
896               enum mesa_debug_severity severity,
897               const char *fmtString, ...)
898{
899   char s[MAX_DEBUG_MESSAGE_LENGTH];
900   int len;
901   va_list args;
902
903   debug_get_id(id);
904
905   va_start(args, fmtString);
906   len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
907   va_end(args);
908
909   _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, type,
910                 *id, severity, len, s);
911}
912
913
914/**
915 * Record an OpenGL state error.  These usually occur when the user
916 * passes invalid parameters to a GL function.
917 *
918 * If debugging is enabled (either at compile-time via the DEBUG macro, or
919 * run-time via the MESA_DEBUG environment variable), report the error with
920 * _mesa_debug().
921 *
922 * \param ctx the GL context.
923 * \param error the error value.
924 * \param fmtString printf() style format string, followed by optional args
925 */
926void
927_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
928{
929   GLboolean do_output, do_log;
930   /* Ideally this would be set up by the caller, so that we had proper IDs
931    * per different message.
932    */
933   static GLuint error_msg_id = 0;
934
935   debug_get_id(&error_msg_id);
936
937   do_output = should_output(ctx, error, fmtString);
938   do_log = should_log(ctx,
939                       MESA_DEBUG_SOURCE_API,
940                       MESA_DEBUG_TYPE_ERROR,
941                       error_msg_id,
942                       MESA_DEBUG_SEVERITY_HIGH);
943
944   if (do_output || do_log) {
945      char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
946      int len;
947      va_list args;
948
949      va_start(args, fmtString);
950      len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
951      va_end(args);
952
953      if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
954         /* Too long error message. Whoever calls _mesa_error should use
955          * shorter strings. */
956         ASSERT(0);
957         return;
958      }
959
960      len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
961                           _mesa_lookup_enum_by_nr(error), s);
962      if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
963         /* Same as above. */
964         ASSERT(0);
965         return;
966      }
967
968      /* Print the error to stderr if needed. */
969      if (do_output) {
970         output_if_debug("Mesa: User error", s2, GL_TRUE);
971      }
972
973      /* Log the error via ARB_debug_output if needed.*/
974      if (do_log) {
975         _mesa_log_msg(ctx,
976                       MESA_DEBUG_SOURCE_API,
977                       MESA_DEBUG_TYPE_ERROR,
978                       error_msg_id,
979                       MESA_DEBUG_SEVERITY_HIGH, len, s2);
980      }
981   }
982
983   /* Set the GL context error state for glGetError. */
984   _mesa_record_error(ctx, error);
985}
986
987
988/**
989 * Report debug information.  Print error message to stderr via fprintf().
990 * No-op if DEBUG mode not enabled.
991 *
992 * \param ctx GL context.
993 * \param fmtString printf()-style format string, followed by optional args.
994 */
995void
996_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
997{
998#ifdef DEBUG
999   char s[MAX_DEBUG_MESSAGE_LENGTH];
1000   va_list args;
1001   va_start(args, fmtString);
1002   _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
1003   va_end(args);
1004   output_if_debug("Mesa", s, GL_FALSE);
1005#endif /* DEBUG */
1006   (void) ctx;
1007   (void) fmtString;
1008}
1009
1010
1011/**
1012 * Report debug information from the shader compiler via GL_ARB_debug_output.
1013 *
1014 * \param ctx GL context.
1015 * \param type The namespace to which this message belongs.
1016 * \param id The message ID within the given namespace.
1017 * \param msg The message to output. Need not be null-terminated.
1018 * \param len The length of 'msg'. If negative, 'msg' must be null-terminated.
1019 */
1020void
1021_mesa_shader_debug( struct gl_context *ctx, GLenum type, GLuint *id,
1022                    const char *msg, int len )
1023{
1024   enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
1025   enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
1026
1027   debug_get_id(id);
1028
1029   if (len < 0)
1030      len = strlen(msg);
1031
1032   /* Truncate the message if necessary. */
1033   if (len >= MAX_DEBUG_MESSAGE_LENGTH)
1034      len = MAX_DEBUG_MESSAGE_LENGTH - 1;
1035
1036   _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
1037}
1038
1039/*@}*/
1040