errors.c revision 5ab088c7e201ea7e55459a24a945abcaa90d12c6
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
33#include "imports.h"
34#include "context.h"
35#include "mtypes.h"
36#include "version.h"
37
38
39#define MAXSTRING 4000  /* for _mesa_vsnprintf() */
40
41/**********************************************************************/
42/** \name Diagnostics */
43/*@{*/
44
45static void
46output_if_debug(const char *prefixString, const char *outputString,
47                GLboolean newline)
48{
49   static int debug = -1;
50
51   /* Check the MESA_DEBUG environment variable if it hasn't
52    * been checked yet.  We only have to check it once...
53    */
54   if (debug == -1) {
55      char *env = _mesa_getenv("MESA_DEBUG");
56
57      /* In a debug build, we print warning messages *unless*
58       * MESA_DEBUG is 0.  In a non-debug build, we don't
59       * print warning messages *unless* MESA_DEBUG is
60       * set *to any value*.
61       */
62#ifdef DEBUG
63      debug = (env != NULL && atoi(env) == 0) ? 0 : 1;
64#else
65      debug = (env != NULL) ? 1 : 0;
66#endif
67   }
68
69   /* Now only print the string if we're required to do so. */
70   if (debug) {
71      fprintf(stderr, "%s: %s", prefixString, outputString);
72      if (newline)
73         fprintf(stderr, "\n");
74
75#if defined(_WIN32) && !defined(_WIN32_WCE)
76      /* stderr from windows applications without console is not usually
77       * visible, so communicate with the debugger instead */
78      {
79         char buf[4096];
80         _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
81         OutputDebugStringA(buf);
82      }
83#endif
84   }
85}
86
87
88/**
89 * Return string version of GL error code.
90 */
91static const char *
92error_string( GLenum error )
93{
94   switch (error) {
95   case GL_NO_ERROR:
96      return "GL_NO_ERROR";
97   case GL_INVALID_VALUE:
98      return "GL_INVALID_VALUE";
99   case GL_INVALID_ENUM:
100      return "GL_INVALID_ENUM";
101   case GL_INVALID_OPERATION:
102      return "GL_INVALID_OPERATION";
103   case GL_STACK_OVERFLOW:
104      return "GL_STACK_OVERFLOW";
105   case GL_STACK_UNDERFLOW:
106      return "GL_STACK_UNDERFLOW";
107   case GL_OUT_OF_MEMORY:
108      return "GL_OUT_OF_MEMORY";
109   case GL_TABLE_TOO_LARGE:
110      return "GL_TABLE_TOO_LARGE";
111   case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
112      return "GL_INVALID_FRAMEBUFFER_OPERATION";
113   default:
114      return "unknown";
115   }
116}
117
118
119/**
120 * When a new type of error is recorded, print a message describing
121 * previous errors which were accumulated.
122 */
123static void
124flush_delayed_errors( struct gl_context *ctx )
125{
126   char s[MAXSTRING];
127
128   if (ctx->ErrorDebugCount) {
129      _mesa_snprintf(s, MAXSTRING, "%d similar %s errors",
130                     ctx->ErrorDebugCount,
131                     error_string(ctx->ErrorValue));
132
133      output_if_debug("Mesa", s, GL_TRUE);
134
135      ctx->ErrorDebugCount = 0;
136   }
137}
138
139
140/**
141 * Report a warning (a recoverable error condition) to stderr if
142 * either DEBUG is defined or the MESA_DEBUG env var is set.
143 *
144 * \param ctx GL context.
145 * \param fmtString printf()-like format string.
146 */
147void
148_mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
149{
150   char str[MAXSTRING];
151   va_list args;
152   va_start( args, fmtString );
153   (void) _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
154   va_end( args );
155
156   if (ctx)
157      flush_delayed_errors( ctx );
158
159   output_if_debug("Mesa warning", str, GL_TRUE);
160}
161
162
163/**
164 * Report an internal implementation problem.
165 * Prints the message to stderr via fprintf().
166 *
167 * \param ctx GL context.
168 * \param fmtString problem description string.
169 */
170void
171_mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
172{
173   va_list args;
174   char str[MAXSTRING];
175   static int numCalls = 0;
176
177   (void) ctx;
178
179   if (numCalls < 50) {
180      numCalls++;
181
182      va_start( args, fmtString );
183      _mesa_vsnprintf( str, MAXSTRING, fmtString, args );
184      va_end( args );
185      fprintf(stderr, "Mesa %s implementation error: %s\n",
186              MESA_VERSION_STRING, str);
187      fprintf(stderr, "Please report at bugs.freedesktop.org\n");
188   }
189}
190
191
192/**
193 * Record an OpenGL state error.  These usually occur when the user
194 * passes invalid parameters to a GL function.
195 *
196 * If debugging is enabled (either at compile-time via the DEBUG macro, or
197 * run-time via the MESA_DEBUG environment variable), report the error with
198 * _mesa_debug().
199 *
200 * \param ctx the GL context.
201 * \param error the error value.
202 * \param fmtString printf() style format string, followed by optional args
203 */
204void
205_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
206{
207   static GLint debug = -1;
208
209   /* Check debug environment variable only once:
210    */
211   if (debug == -1) {
212      const char *debugEnv = _mesa_getenv("MESA_DEBUG");
213
214#ifdef DEBUG
215      if (debugEnv && strstr(debugEnv, "silent"))
216         debug = GL_FALSE;
217      else
218         debug = GL_TRUE;
219#else
220      if (debugEnv)
221         debug = GL_TRUE;
222      else
223         debug = GL_FALSE;
224#endif
225   }
226
227   if (debug) {
228      if (ctx->ErrorValue == error &&
229          ctx->ErrorDebugFmtString == fmtString) {
230         ctx->ErrorDebugCount++;
231      }
232      else {
233         char s[MAXSTRING], s2[MAXSTRING];
234         va_list args;
235
236         flush_delayed_errors( ctx );
237
238         va_start(args, fmtString);
239         _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
240         va_end(args);
241
242         _mesa_snprintf(s2, MAXSTRING, "%s in %s", error_string(error), s);
243         output_if_debug("Mesa: User error", s2, GL_TRUE);
244
245         ctx->ErrorDebugFmtString = fmtString;
246         ctx->ErrorDebugCount = 0;
247      }
248   }
249
250   _mesa_record_error(ctx, error);
251}
252
253
254/**
255 * Report debug information.  Print error message to stderr via fprintf().
256 * No-op if DEBUG mode not enabled.
257 *
258 * \param ctx GL context.
259 * \param fmtString printf()-style format string, followed by optional args.
260 */
261void
262_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
263{
264#ifdef DEBUG
265   char s[MAXSTRING];
266   va_list args;
267   va_start(args, fmtString);
268   _mesa_vsnprintf(s, MAXSTRING, fmtString, args);
269   va_end(args);
270   output_if_debug("Mesa", s, GL_FALSE);
271#endif /* DEBUG */
272   (void) ctx;
273   (void) fmtString;
274}
275
276/*@}*/
277