xref: /aosp_15_r20/external/mesa3d/src/mesa/main/errors.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 
36 #include "context.h"
37 #include "debug_output.h"
38 #include "util/detect_os.h"
39 #include "util/log.h"
40 #include "api_exec_decl.h"
41 
42 /**
43  * When a new type of error is recorded, print a message describing
44  * previous errors which were accumulated.
45  */
46 static void
flush_delayed_errors(struct gl_context * ctx)47 flush_delayed_errors( struct gl_context *ctx )
48 {
49    char s[MAX_DEBUG_MESSAGE_LENGTH];
50 
51    if (ctx->ErrorDebugCount) {
52       snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors",
53                      ctx->ErrorDebugCount,
54                      _mesa_enum_to_string(ctx->ErrorValue));
55 
56       mesa_log_if_debug(MESA_LOG_ERROR, s);
57 
58       ctx->ErrorDebugCount = 0;
59    }
60 }
61 
62 
63 /**
64  * Report a warning (a recoverable error condition) to stderr if
65  * either MESA_DEBUG is defined to 1 or the MESA_DEBUG env var is set.
66  *
67  * \param ctx GL context.
68  * \param fmtString printf()-like format string.
69  */
70 void
_mesa_warning(struct gl_context * ctx,const char * fmtString,...)71 _mesa_warning( struct gl_context *ctx, const char *fmtString, ... )
72 {
73    char str[MAX_DEBUG_MESSAGE_LENGTH];
74    va_list args;
75    va_start( args, fmtString );
76    (void) vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
77    va_end( args );
78 
79    if (ctx)
80       flush_delayed_errors( ctx );
81 
82    mesa_log_if_debug(MESA_LOG_WARN, str);
83 }
84 
85 
86 /**
87  * Report an internal implementation problem.
88  * Prints the message to stderr via fprintf().
89  *
90  * \param ctx GL context.
91  * \param fmtString problem description string.
92  */
93 void
_mesa_problem(const struct gl_context * ctx,const char * fmtString,...)94 _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... )
95 {
96    va_list args;
97    char str[MAX_DEBUG_MESSAGE_LENGTH];
98    static int numCalls = 0;
99 
100    (void) ctx;
101 
102    if (numCalls < 50) {
103       numCalls++;
104 
105       va_start( args, fmtString );
106       vsnprintf( str, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args );
107       va_end( args );
108       fprintf(stderr, "Mesa " PACKAGE_VERSION " implementation error: %s\n",
109               str);
110       fprintf(stderr, "Please report at " PACKAGE_BUGREPORT "\n");
111    }
112 }
113 
114 
115 static GLboolean
should_output(struct gl_context * ctx,GLenum error,const char * fmtString)116 should_output(struct gl_context *ctx, GLenum error, const char *fmtString)
117 {
118    static GLint debug = -1;
119 
120    /* Check debug environment variable only once:
121     */
122    if (debug == -1) {
123       const char *debugEnv = getenv("MESA_DEBUG");
124 
125 #ifndef NDEBUG
126       if (debugEnv && strstr(debugEnv, "silent"))
127          debug = GL_FALSE;
128       else
129          debug = GL_TRUE;
130 #else
131       if (debugEnv)
132          debug = GL_TRUE;
133       else
134          debug = GL_FALSE;
135 #endif
136    }
137 
138    if (debug) {
139       if (ctx->ErrorValue != error ||
140           ctx->ErrorDebugFmtString != fmtString) {
141          flush_delayed_errors( ctx );
142          ctx->ErrorDebugFmtString = fmtString;
143          ctx->ErrorDebugCount = 0;
144          return GL_TRUE;
145       }
146       ctx->ErrorDebugCount++;
147    }
148    return GL_FALSE;
149 }
150 
151 
152 void
_mesa_gl_vdebugf(struct gl_context * ctx,GLuint * id,enum mesa_debug_source source,enum mesa_debug_type type,enum mesa_debug_severity severity,const char * fmtString,va_list args)153 _mesa_gl_vdebugf(struct gl_context *ctx,
154                  GLuint *id,
155                  enum mesa_debug_source source,
156                  enum mesa_debug_type type,
157                  enum mesa_debug_severity severity,
158                  const char *fmtString,
159                  va_list args)
160 {
161    char s[MAX_DEBUG_MESSAGE_LENGTH];
162    int len;
163 
164    _mesa_debug_get_id(id);
165 
166    len = vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
167    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
168       /* message was truncated */
169       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
170 
171    _mesa_log_msg(ctx, source, type, *id, severity, len, s);
172 }
173 
174 
175 void
_mesa_gl_debugf(struct gl_context * ctx,GLuint * id,enum mesa_debug_source source,enum mesa_debug_type type,enum mesa_debug_severity severity,const char * fmtString,...)176 _mesa_gl_debugf(struct gl_context *ctx,
177                 GLuint *id,
178                 enum mesa_debug_source source,
179                 enum mesa_debug_type type,
180                 enum mesa_debug_severity severity,
181                 const char *fmtString, ...)
182 {
183    va_list args;
184    va_start(args, fmtString);
185    _mesa_gl_vdebugf(ctx, id, source, type, severity, fmtString, args);
186    va_end(args);
187 }
188 
189 size_t
_mesa_gl_debug(struct gl_context * ctx,GLuint * id,enum mesa_debug_source source,enum mesa_debug_type type,enum mesa_debug_severity severity,const char * msg)190 _mesa_gl_debug(struct gl_context *ctx,
191                GLuint *id,
192                enum mesa_debug_source source,
193                enum mesa_debug_type type,
194                enum mesa_debug_severity severity,
195                const char *msg)
196 {
197    _mesa_debug_get_id(id);
198 
199    size_t len = strnlen(msg, MAX_DEBUG_MESSAGE_LENGTH);
200    if (len < MAX_DEBUG_MESSAGE_LENGTH) {
201       _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
202       return len;
203    }
204 
205    /* limit the message to fit within KHR_debug buffers */
206    char s[MAX_DEBUG_MESSAGE_LENGTH];
207    strncpy(s, msg, MAX_DEBUG_MESSAGE_LENGTH - 1);
208    s[MAX_DEBUG_MESSAGE_LENGTH - 1] = '\0';
209    len = MAX_DEBUG_MESSAGE_LENGTH - 1;
210    _mesa_log_msg(ctx, source, type, *id, severity, len, s);
211 
212    /* report the number of characters that were logged */
213    return len;
214 }
215 
216 
217 /**
218  * Record an OpenGL state error.  These usually occur when the user
219  * passes invalid parameters to a GL function.
220  *
221  * If debugging is enabled (either at compile-time via the MESA_DEBUG macro, or
222  * run-time via the MESA_DEBUG environment variable), report the error with
223  * _mesa_debug().
224  *
225  * \param ctx the GL context.
226  * \param error the error value.
227  * \param fmtString printf() style format string, followed by optional args
228  */
229 void
_mesa_error(struct gl_context * ctx,GLenum error,const char * fmtString,...)230 _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
231 {
232    GLboolean do_output, do_log;
233    /* Ideally this would be set up by the caller, so that we had proper IDs
234     * per different message.
235     */
236    static GLuint error_msg_id = 0;
237 
238    _mesa_debug_get_id(&error_msg_id);
239 
240    do_output = should_output(ctx, error, fmtString);
241 
242    simple_mtx_lock(&ctx->DebugMutex);
243    if (ctx->Debug) {
244       do_log = _mesa_debug_is_message_enabled(ctx->Debug,
245                                               MESA_DEBUG_SOURCE_API,
246                                               MESA_DEBUG_TYPE_ERROR,
247                                               error_msg_id,
248                                               MESA_DEBUG_SEVERITY_HIGH);
249    }
250    else {
251       do_log = GL_FALSE;
252    }
253    simple_mtx_unlock(&ctx->DebugMutex);
254 
255    if (do_output || do_log) {
256       char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH];
257       int len;
258       va_list args;
259 
260       va_start(args, fmtString);
261       len = vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
262       va_end(args);
263 
264       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
265          /* Too long error message. Whoever calls _mesa_error should use
266           * shorter strings.
267           */
268          assert(0);
269          return;
270       }
271 
272       len = snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s",
273                            _mesa_enum_to_string(error), s);
274       if (len >= MAX_DEBUG_MESSAGE_LENGTH) {
275          /* Same as above. */
276          assert(0);
277          return;
278       }
279 
280       /* Print the error to stderr if needed. */
281       if (do_output) {
282          mesa_log_if_debug(MESA_LOG_ERROR, s2);
283       }
284 
285       /* Log the error via ARB_debug_output if needed.*/
286       if (do_log) {
287          _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR,
288                        error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2);
289       }
290    }
291 
292    /* Set the GL context error state for glGetError. */
293    if (ctx->ErrorValue == GL_NO_ERROR)
294       ctx->ErrorValue = error;
295 }
296 
297 void
_mesa_error_no_memory(const char * caller)298 _mesa_error_no_memory(const char *caller)
299 {
300    GET_CURRENT_CONTEXT(ctx);
301    _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller);
302 }
303 
304 /**
305  * Report debug information.  Print error message to stderr via fprintf()
306  * when debug mode is enabled by NDEBUG; otherwise no-op.
307  *
308  * \param ctx GL context.
309  * \param fmtString printf()-style format string, followed by optional args.
310  */
311 void
_mesa_debug(const struct gl_context * ctx,const char * fmtString,...)312 _mesa_debug( const struct gl_context *ctx, const char *fmtString, ... )
313 {
314 #ifndef NDEBUG
315    char s[MAX_DEBUG_MESSAGE_LENGTH];
316    va_list args;
317    va_start(args, fmtString);
318    vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args);
319    va_end(args);
320    mesa_log_if_debug(MESA_LOG_DEBUG, s);
321 #endif /* !NDEBUG */
322    (void) ctx;
323    (void) fmtString;
324 }
325 
326 /**
327  * Report debug information from the shader compiler via GL_ARB_debug_output.
328  *
329  * \param ctx GL context.
330  * \param type The namespace to which this message belongs.
331  * \param id The message ID within the given namespace.
332  * \param msg The message to output. Must be null-terminated.
333  */
334 void
_mesa_shader_debug(struct gl_context * ctx,GLenum type,GLuint * id,const char * msg)335 _mesa_shader_debug(struct gl_context *ctx, GLenum type, GLuint *id,
336                    const char *msg)
337 {
338    enum mesa_debug_source source = MESA_DEBUG_SOURCE_SHADER_COMPILER;
339    enum mesa_debug_severity severity = MESA_DEBUG_SEVERITY_HIGH;
340    int len;
341 
342    _mesa_debug_get_id(id);
343 
344    len = strlen(msg);
345 
346    /* Truncate the message if necessary. */
347    if (len >= MAX_DEBUG_MESSAGE_LENGTH)
348       len = MAX_DEBUG_MESSAGE_LENGTH - 1;
349 
350    _mesa_log_msg(ctx, source, type, *id, severity, len, msg);
351 }
352 
353 /**
354  * Set the parameter as the current GL error. Used by glthread.
355  */
356 void GLAPIENTRY
_mesa_InternalSetError(GLenum error)357 _mesa_InternalSetError(GLenum error)
358 {
359    GET_CURRENT_CONTEXT(ctx);
360    _mesa_error(ctx, error, "glthread");
361 }
362