OSDN Git Service

Merge remote-tracking branch 'mesa/18.3' into oreo-x86
[android-x86/external-mesa.git] / src / mesa / main / errors.c
1 /**
2  * \file errors.c
3  * Mesa debugging and error handling functions.
4  */
5
6 /*
7  * Mesa 3-D graphics library
8  *
9  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  * OTHER DEALINGS IN THE SOFTWARE.
28  */
29
30
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include "errors.h"
34 #include "enums.h"
35 #include "imports.h"
36 #include "context.h"
37 #include "debug_output.h"
38
39 #if defined(ANDROID)
40 #  define LOG_TAG "mesa"
41 #  include <log/log.h>
42 #endif
43
44 static FILE *LogFile = NULL;
45
46
47 static void
48 output_if_debug(const char *prefixString, const char *outputString,
49                 GLboolean newline)
50 {
51    static int debug = -1;
52
53    /* Init the local 'debug' var once.
54     * Note: the _mesa_init_debug() function should have been called
55     * by now so MESA_DEBUG_FLAGS will be initialized.
56     */
57    if (debug == -1) {
58       /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings,
59        * etc to the named file.  Otherwise, output to stderr.
60        */
61       const char *logFile = getenv("MESA_LOG_FILE");
62       if (logFile)
63          LogFile = fopen(logFile, "w");
64       if (!LogFile)
65          LogFile = stderr;
66 #ifdef DEBUG
67       /* in debug builds, print messages unless MESA_DEBUG="silent" */
68       if (MESA_DEBUG_FLAGS & DEBUG_SILENT)
69          debug = 0;
70       else
71          debug = 1;
72 #else
73       /* in release builds, be silent unless MESA_DEBUG is set */
74       debug = getenv("MESA_DEBUG") != NULL;
75 #endif
76    }
77
78    /* Now only print the string if we're required to do so. */
79    if (debug) {
80       if (prefixString)
81          fprintf(LogFile, "%s: %s", prefixString, outputString);
82       else
83          fprintf(LogFile, "%s", outputString);
84       if (newline)
85          fprintf(LogFile, "\n");
86       fflush(LogFile);
87
88 #if defined(_WIN32)
89       /* stderr from windows applications without console is not usually 
90        * visible, so communicate with the debugger instead */ 
91       {
92          char buf[4096];
93          _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : "");
94          OutputDebugStringA(buf);
95       }
96 #elif defined(ANDROID)
97       {
98          ALOGD("%s: %s", prefixString, outputString);
99       }
100 #endif
101    }
102 }
103
104
105 /**
106  * Return the file handle to use for debug/logging.  Defaults to stderr
107  * unless MESA_LOG_FILE is defined.
108  */
109 FILE *
110 _mesa_get_log_file(void)
111 {
112    assert(LogFile);
113    return LogFile;
114 }
115
116
117 /**
118  * When a new type of error is recorded, print a message describing
119  * previous errors which were accumulated.
120  */
121 static void
122 flush_delayed_errors( struct gl_context *ctx )
123 {
124    char s[MAX_DEBUG_MESSAGE_LENGTH];
125
126    if (ctx->ErrorDebugCount) {
127       _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
128                      ctx->ErrorDebugCount,
129                      _mesa_enum_to_string(ctx->ErrorValue));
130
131       output_if_debug("Mesa", s, GL_TRUE);
132
133       ctx->ErrorDebugCount = 0;
134    }
135 }
136
137
138 /**
139  * Report a warning (a recoverable error condition) to stderr if
140  * either DEBUG is defined or the MESA_DEBUG env var is set.
141  *
142  * \param ctx GL context.
143  * \param fmtString printf()-like format string.
144  */
145 void
146 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
147 {
148    char str[MAX_DEBUG_MESSAGE_LENGTH];
149    va_list args;
150    va_start( args, fmtString );
151    (void) _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
152    va_end( args );
153
154    if (ctx)
155       flush_delayed_errors( ctx );
156
157    output_if_debug("Mesa warning", str, GL_TRUE);
158 }
159
160
161 /**
162  * Report an internal implementation problem.
163  * Prints the message to stderr via fprintf().
164  *
165  * \param ctx GL context.
166  * \param fmtString problem description string.
167  */
168 void
169 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
170 {
171    va_list args;
172    char str[MAX_DEBUG_MESSAGE_LENGTH];
173    static int numCalls = 0;
174
175    (void) ctx;
176
177    if (numCalls < 50) {
178       numCalls++;
179
180       va_start( args, fmtString );
181       _mesa_vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
182       va_end( args );
183       fprintf(stderr, "Mesa " PACKAGE_VERSION " implementation error: %s\n",
184               str);
185       fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
186    }
187 }
188
189
190 static GLboolean
191 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
192 {
193    static GLint debug = -1;
194
195    /* Check debug environment variable only once:
196     */
197    if (debug == -1) {
198       const char *debugEnv = getenv("MESA_DEBUG");
199
200 #ifdef DEBUG
201       if (debugEnv && strstr(debugEnv, "silent"))
202          debug = GL_FALSE;
203       else
204          debug = GL_TRUE;
205 #else
206       if (debugEnv)
207          debug = GL_TRUE;
208       else
209          debug = GL_FALSE;
210 #endif
211    }
212
213    if (debug) {
214       if (ctx->ErrorValue != error ||
215           ctx->ErrorDebugFmtString != fmtString) {
216          flush_delayed_errors( ctx );
217          ctx->ErrorDebugFmtString = fmtString;
218          ctx->ErrorDebugCount = 0;
219          return GL_TRUE;
220       }
221       ctx->ErrorDebugCount++;
222    }
223    return GL_FALSE;
224 }
225
226
227 void
228 _mesa_gl_vdebug(struct gl_context *ctx,
229                 GLuint *id,
230                 enum mesa_debug_source source,
231                 enum mesa_debug_type type,
232                 enum mesa_debug_severity severity,
233                 const char *fmtString,
234                 va_list args)
235 {
236    char s[MAX_DEBUG_MESSAGE_LENGTH];
237    int len;
238
239    _mesa_debug_get_id(id);
240
241    len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
242    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
243       /* message was truncated */
244       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
245
246    _mesa_log_msg(ctx, source, type, *id, severity, len, s);
247 }
248
249
250 void
251 _mesa_gl_debug(struct gl_context *ctx,
252                GLuint *id,
253                enum mesa_debug_source source,
254                enum mesa_debug_type type,
255                enum mesa_debug_severity severity,
256                const char *fmtString, ...)
257 {
258    va_list args;
259    va_start(args, fmtString);
260    _mesa_gl_vdebug(ctx, id, source, type, severity, fmtString, args);
261    va_end(args);
262 }
263
264
265 /**
266  * Record an OpenGL state error.  These usually occur when the user
267  * passes invalid parameters to a GL function.
268  *
269  * If debugging is enabled (either at compile-time via the DEBUG macro, or
270  * run-time via the MESA_DEBUG environment variable), report the error with
271  * _mesa_debug().
272  *
273  * \param ctx the GL context.
274  * \param error the error value.
275  * \param fmtString printf() style format string, followed by optional args
276  */
277 void
278 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
279 {
280    GLboolean do_output, do_log;
281    /* Ideally this would be set up by the caller, so that we had proper IDs
282     * per different message.
283     */
284    static GLuint error_msg_id = 0;
285
286    _mesa_debug_get_id(&error_msg_id);
287
288    do_output = should_output(ctx, error, fmtString);
289
290    simple_mtx_lock(&ctx->DebugMutex);
291    if (ctx->Debug) {
292       do_log = _mesa_debug_is_message_enabled(ctx->Debug,
293                                               MESA_DEBUG_SOURCE_API,
294                                               MESA_DEBUG_TYPE_ERROR,
295                                               error_msg_id,
296                                               MESA_DEBUG_SEVERITY_HIGH);
297    }
298    else {
299       do_log = GL_FALSE;
300    }
301    simple_mtx_unlock(&ctx->DebugMutex);
302
303    if (do_output || do_log) {
304       char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
305       int len;
306       va_list args;
307
308       va_start(args, fmtString);
309       len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
310       va_end(args);
311
312       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
313          /* Too long error message. Whoever calls _mesa_error should use
314           * shorter strings.
315           */
316          assert(0);
317          return;
318       }
319
320       len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
321                            _mesa_enum_to_string(error), s);
322       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
323          /* Same as above. */
324          assert(0);
325          return;
326       }
327
328       /* Print the error to stderr if needed. */
329       if (do_output) {
330          output_if_debug("Mesa: User error", s2, GL_TRUE);
331       }
332
333       /* Log the error via ARB_debug_output if needed.*/
334       if (do_log) {
335          _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR,
336                        error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2);
337       }
338    }
339
340    /* Set the GL context error state for glGetError. */
341    if (ctx->ErrorValue == GL_NO_ERROR)
342       ctx->ErrorValue = error;
343 }
344
345 void
346 _mesa_error_no_memory(const char *caller)
347 {
348    GET_CURRENT_CONTEXT(ctx);
349    _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller);
350 }
351
352 /**
353  * Report debug information.  Print error message to stderr via fprintf().
354  * No-op if DEBUG mode not enabled.
355  *
356  * \param ctx GL context.
357  * \param fmtString printf()-style format string, followed by optional args.
358  */
359 void
360 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
361 {
362 #ifdef DEBUG
363    char s[MAX_DEBUG_MESSAGE_LENGTH];
364    va_list args;
365    va_start(args, fmtString);
366    _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
367    va_end(args);
368    output_if_debug("Mesa", s, GL_FALSE);
369 #endif /* DEBUG */
370    (void) ctx;
371    (void) fmtString;
372 }
373
374
375 void
376 _mesa_log(const char *fmtString, ...)
377 {
378    char s[MAX_DEBUG_MESSAGE_LENGTH];
379    va_list args;
380    va_start(args, fmtString);
381    _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
382    va_end(args);
383    output_if_debug("", s, GL_FALSE);
384 }
385
386
387 /**
388  * Report debug information from the shader compiler via GL_ARB_debug_output.
389  *
390  * \param ctx GL context.
391  * \param type The namespace to which this message belongs.
392  * \param id The message ID within the given namespace.
393  * \param msg The message to output. Must be null-terminated.
394  */
395 void
396 _mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id,
397                    const char *msg)
398 {
399    enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
400    enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
401    int len;
402
403    _mesa_debug_get_id(id);
404
405    len = strlen(msg);
406
407    /* Truncate the message if necessary. */
408    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
409       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
410
411    _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
412 }