• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2008 VMware, Inc.
4  * Copyright (c) 2008 VMware, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 
30 #include "pipe/p_config.h"
31 
32 #include "pipe/p_compiler.h"
33 #include "util/u_debug.h"
34 #include "util/u_dump.h"
35 #include "pipe/p_format.h"
36 #include "pipe/p_state.h"
37 #include "util/u_inlines.h"
38 #include "util/u_format.h"
39 #include "util/u_memory.h"
40 #include "util/u_string.h"
41 #include "util/u_math.h"
42 #include "util/u_prim.h"
43 #include <inttypes.h>
44 
45 #include <stdio.h>
46 #include <limits.h> /* CHAR_BIT */
47 #include <ctype.h> /* isalnum */
48 
49 #ifdef _WIN32
50 #include <windows.h>
51 #include <stdlib.h>
52 #endif
53 
54 
55 void
_debug_vprintf(const char * format,va_list ap)56 _debug_vprintf(const char *format, va_list ap)
57 {
58    static char buf[4096] = {'\0'};
59 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
60    /* We buffer until we find a newline. */
61    size_t len = strlen(buf);
62    int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
63    if (ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
64       os_log_message(buf);
65       buf[0] = '\0';
66    }
67 #else
68    util_vsnprintf(buf, sizeof(buf), format, ap);
69    os_log_message(buf);
70 #endif
71 }
72 
73 
74 void
_pipe_debug_message(struct pipe_debug_callback * cb,unsigned * id,enum pipe_debug_type type,const char * fmt,...)75 _pipe_debug_message(struct pipe_debug_callback *cb,
76                     unsigned *id,
77                     enum pipe_debug_type type,
78                     const char *fmt, ...)
79 {
80    va_list args;
81    va_start(args, fmt);
82    if (cb && cb->debug_message)
83       cb->debug_message(cb->data, id, type, fmt, args);
84    va_end(args);
85 }
86 
87 
88 void
debug_disable_error_message_boxes(void)89 debug_disable_error_message_boxes(void)
90 {
91 #ifdef _WIN32
92    /* When Windows' error message boxes are disabled for this process (as is
93     * typically the case when running tests in an automated fashion) we disable
94     * CRT message boxes too.
95     */
96    UINT uMode = SetErrorMode(0);
97    SetErrorMode(uMode);
98    if (uMode & SEM_FAILCRITICALERRORS) {
99       /* Disable assertion failure message box.
100        * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
101        */
102       _set_error_mode(_OUT_TO_STDERR);
103 #ifdef _MSC_VER
104       /* Disable abort message box.
105        * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
106        */
107       _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
108 #endif
109    }
110 #endif /* _WIN32 */
111 }
112 
113 
114 #ifdef DEBUG
115 void
debug_print_blob(const char * name,const void * blob,unsigned size)116 debug_print_blob(const char *name, const void *blob, unsigned size)
117 {
118    const unsigned *ublob = (const unsigned *)blob;
119    unsigned i;
120 
121    debug_printf("%s (%d dwords%s)\n", name, size/4,
122                 size%4 ? "... plus a few bytes" : "");
123 
124    for (i = 0; i < size/4; i++) {
125       debug_printf("%d:\t%08x\n", i, ublob[i]);
126    }
127 }
128 #endif
129 
130 
131 static boolean
debug_get_option_should_print(void)132 debug_get_option_should_print(void)
133 {
134    static boolean first = TRUE;
135    static boolean value = FALSE;
136 
137    if (!first)
138       return value;
139 
140    /* Oh hey this will call into this function,
141     * but its cool since we set first to false
142     */
143    first = FALSE;
144    value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
145    /* XXX should we print this option? Currently it wont */
146    return value;
147 }
148 
149 
150 const char *
debug_get_option(const char * name,const char * dfault)151 debug_get_option(const char *name, const char *dfault)
152 {
153    const char *result;
154 
155    result = os_get_option(name);
156    if (!result)
157       result = dfault;
158 
159    if (debug_get_option_should_print())
160       debug_printf("%s: %s = %s\n", __FUNCTION__, name,
161                    result ? result : "(null)");
162 
163    return result;
164 }
165 
166 
167 boolean
debug_get_bool_option(const char * name,boolean dfault)168 debug_get_bool_option(const char *name, boolean dfault)
169 {
170    const char *str = os_get_option(name);
171    boolean result;
172 
173    if (str == NULL)
174       result = dfault;
175    else if (!util_strcmp(str, "n"))
176       result = FALSE;
177    else if (!util_strcmp(str, "no"))
178       result = FALSE;
179    else if (!util_strcmp(str, "0"))
180       result = FALSE;
181    else if (!util_strcmp(str, "f"))
182       result = FALSE;
183    else if (!util_strcmp(str, "F"))
184       result = FALSE;
185    else if (!util_strcmp(str, "false"))
186       result = FALSE;
187    else if (!util_strcmp(str, "FALSE"))
188       result = FALSE;
189    else
190       result = TRUE;
191 
192    if (debug_get_option_should_print())
193       debug_printf("%s: %s = %s\n", __FUNCTION__, name,
194                    result ? "TRUE" : "FALSE");
195 
196    return result;
197 }
198 
199 
200 long
debug_get_num_option(const char * name,long dfault)201 debug_get_num_option(const char *name, long dfault)
202 {
203    long result;
204    const char *str;
205 
206    str = os_get_option(name);
207    if (!str) {
208       result = dfault;
209    } else {
210       char *endptr;
211 
212       result = strtol(str, &endptr, 0);
213       if (str == endptr) {
214          /* Restore the default value when no digits were found. */
215          result = dfault;
216       }
217    }
218 
219    if (debug_get_option_should_print())
220       debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
221 
222    return result;
223 }
224 
225 
226 static boolean
str_has_option(const char * str,const char * name)227 str_has_option(const char *str, const char *name)
228 {
229    /* Empty string. */
230    if (!*str) {
231       return FALSE;
232    }
233 
234    /* OPTION=all */
235    if (!util_strcmp(str, "all")) {
236       return TRUE;
237    }
238 
239    /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
240    {
241       const char *start = str;
242       unsigned name_len = strlen(name);
243 
244       /* 'start' is the beginning of the currently-parsed word,
245        * we increment 'str' each iteration.
246        * if we find either the end of string or a non-alphanumeric character,
247        * we compare 'start' up to 'str-1' with 'name'. */
248 
249       while (1) {
250          if (!*str || !(isalnum(*str) || *str == '_')) {
251             if (str-start == name_len &&
252                 !memcmp(start, name, name_len)) {
253                return TRUE;
254             }
255 
256             if (!*str) {
257                return FALSE;
258             }
259 
260             start = str+1;
261          }
262 
263          str++;
264       }
265    }
266 
267    return FALSE;
268 }
269 
270 
271 uint64_t
debug_get_flags_option(const char * name,const struct debug_named_value * flags,uint64_t dfault)272 debug_get_flags_option(const char *name,
273                        const struct debug_named_value *flags,
274                        uint64_t dfault)
275 {
276    uint64_t result;
277    const char *str;
278    const struct debug_named_value *orig = flags;
279    unsigned namealign = 0;
280 
281    str = os_get_option(name);
282    if (!str)
283       result = dfault;
284    else if (!util_strcmp(str, "help")) {
285       result = dfault;
286       _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
287       for (; flags->name; ++flags)
288          namealign = MAX2(namealign, strlen(flags->name));
289       for (flags = orig; flags->name; ++flags)
290          _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
291                       (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
292                       flags->desc ? " " : "", flags->desc ? flags->desc : "");
293    }
294    else {
295       result = 0;
296       while (flags->name) {
297 	 if (str_has_option(str, flags->name))
298 	    result |= flags->value;
299 	 ++flags;
300       }
301    }
302 
303    if (debug_get_option_should_print()) {
304       if (str) {
305          debug_printf("%s: %s = 0x%"PRIx64" (%s)\n",
306                       __FUNCTION__, name, result, str);
307       } else {
308          debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
309       }
310    }
311 
312    return result;
313 }
314 
315 
316 void
_debug_assert_fail(const char * expr,const char * file,unsigned line,const char * function)317 _debug_assert_fail(const char *expr, const char *file, unsigned line,
318                    const char *function)
319 {
320    _debug_printf("%s:%u:%s: Assertion `%s' failed.\n",
321                  file, line, function, expr);
322    os_abort();
323 }
324 
325 
326 const char *
debug_dump_enum(const struct debug_named_value * names,unsigned long value)327 debug_dump_enum(const struct debug_named_value *names,
328                 unsigned long value)
329 {
330    static char rest[64];
331 
332    while (names->name) {
333       if (names->value == value)
334 	 return names->name;
335       ++names;
336    }
337 
338    util_snprintf(rest, sizeof(rest), "0x%08lx", value);
339    return rest;
340 }
341 
342 
343 const char *
debug_dump_enum_noprefix(const struct debug_named_value * names,const char * prefix,unsigned long value)344 debug_dump_enum_noprefix(const struct debug_named_value *names,
345                          const char *prefix,
346                          unsigned long value)
347 {
348    static char rest[64];
349 
350    while (names->name) {
351       if (names->value == value) {
352          const char *name = names->name;
353          while (*name == *prefix) {
354             name++;
355             prefix++;
356          }
357          return name;
358       }
359       ++names;
360    }
361 
362    util_snprintf(rest, sizeof(rest), "0x%08lx", value);
363    return rest;
364 }
365 
366 
367 const char *
debug_dump_flags(const struct debug_named_value * names,unsigned long value)368 debug_dump_flags(const struct debug_named_value *names, unsigned long value)
369 {
370    static char output[4096];
371    static char rest[256];
372    int first = 1;
373 
374    output[0] = '\0';
375 
376    while (names->name) {
377       if ((names->value & value) == names->value) {
378 	 if (!first)
379 	    util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
380 	 else
381 	    first = 0;
382 	 util_strncat(output, names->name, sizeof(output) - strlen(output) - 1);
383 	 output[sizeof(output) - 1] = '\0';
384 	 value &= ~names->value;
385       }
386       ++names;
387    }
388 
389    if (value) {
390       if (!first)
391 	 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
392       else
393 	 first = 0;
394 
395       util_snprintf(rest, sizeof(rest), "0x%08lx", value);
396       util_strncat(output, rest, sizeof(output) - strlen(output) - 1);
397       output[sizeof(output) - 1] = '\0';
398    }
399 
400    if (first)
401       return "0";
402 
403    return output;
404 }
405 
406 
407 #ifdef DEBUG
408 void
debug_print_format(const char * msg,unsigned fmt)409 debug_print_format(const char *msg, unsigned fmt )
410 {
411    debug_printf("%s: %s\n", msg, util_format_name(fmt));
412 }
413 #endif
414 
415 
416 /** Return string name of given primitive type */
417 const char *
u_prim_name(enum pipe_prim_type prim)418 u_prim_name(enum pipe_prim_type prim)
419 {
420    static const struct debug_named_value names[] = {
421       DEBUG_NAMED_VALUE(PIPE_PRIM_POINTS),
422       DEBUG_NAMED_VALUE(PIPE_PRIM_LINES),
423       DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_LOOP),
424       DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP),
425       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES),
426       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP),
427       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_FAN),
428       DEBUG_NAMED_VALUE(PIPE_PRIM_QUADS),
429       DEBUG_NAMED_VALUE(PIPE_PRIM_QUAD_STRIP),
430       DEBUG_NAMED_VALUE(PIPE_PRIM_POLYGON),
431       DEBUG_NAMED_VALUE(PIPE_PRIM_LINES_ADJACENCY),
432       DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP_ADJACENCY),
433       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES_ADJACENCY),
434       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY),
435       DEBUG_NAMED_VALUE_END
436    };
437    return debug_dump_enum(names, prim);
438 }
439 
440 
441 
442 #ifdef DEBUG
443 int fl_indent = 0;
444 const char* fl_function[1024];
445 
446 int
debug_funclog_enter(const char * f,UNUSED const int line,UNUSED const char * file)447 debug_funclog_enter(const char* f, UNUSED const int line,
448                     UNUSED const char* file)
449 {
450    int i;
451 
452    for (i = 0; i < fl_indent; i++)
453       debug_printf("  ");
454    debug_printf("%s\n", f);
455 
456    assert(fl_indent < 1023);
457    fl_function[fl_indent++] = f;
458 
459    return 0;
460 }
461 
462 void
debug_funclog_exit(const char * f,UNUSED const int line,UNUSED const char * file)463 debug_funclog_exit(const char* f, UNUSED const int line,
464                    UNUSED const char* file)
465 {
466    --fl_indent;
467    assert(fl_indent >= 0);
468    assert(fl_function[fl_indent] == f);
469 }
470 
471 void
debug_funclog_enter_exit(const char * f,UNUSED const int line,UNUSED const char * file)472 debug_funclog_enter_exit(const char* f, UNUSED const int line,
473                          UNUSED const char* file)
474 {
475    int i;
476    for (i = 0; i < fl_indent; i++)
477       debug_printf("  ");
478    debug_printf("%s\n", f);
479 }
480 #endif
481 
482 
483 
484 #ifdef DEBUG
485 /**
486  * Print PIPE_TRANSFER_x flags with a message.
487  */
488 void
debug_print_transfer_flags(const char * msg,unsigned usage)489 debug_print_transfer_flags(const char *msg, unsigned usage)
490 {
491    debug_printf("%s: ", msg);
492    util_dump_transfer_usage(stdout, usage);
493    printf("\n");
494 }
495 
496 
497 /**
498  * Print PIPE_BIND_x flags with a message.
499  */
500 void
debug_print_bind_flags(const char * msg,unsigned usage)501 debug_print_bind_flags(const char *msg, unsigned usage)
502 {
503    static const struct debug_named_value names[] = {
504       DEBUG_NAMED_VALUE(PIPE_BIND_DEPTH_STENCIL),
505       DEBUG_NAMED_VALUE(PIPE_BIND_RENDER_TARGET),
506       DEBUG_NAMED_VALUE(PIPE_BIND_BLENDABLE),
507       DEBUG_NAMED_VALUE(PIPE_BIND_SAMPLER_VIEW),
508       DEBUG_NAMED_VALUE(PIPE_BIND_VERTEX_BUFFER),
509       DEBUG_NAMED_VALUE(PIPE_BIND_INDEX_BUFFER),
510       DEBUG_NAMED_VALUE(PIPE_BIND_CONSTANT_BUFFER),
511       DEBUG_NAMED_VALUE(PIPE_BIND_DISPLAY_TARGET),
512       DEBUG_NAMED_VALUE(PIPE_BIND_STREAM_OUTPUT),
513       DEBUG_NAMED_VALUE(PIPE_BIND_CURSOR),
514       DEBUG_NAMED_VALUE(PIPE_BIND_CUSTOM),
515       DEBUG_NAMED_VALUE(PIPE_BIND_GLOBAL),
516       DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_BUFFER),
517       DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_IMAGE),
518       DEBUG_NAMED_VALUE(PIPE_BIND_COMPUTE_RESOURCE),
519       DEBUG_NAMED_VALUE(PIPE_BIND_COMMAND_ARGS_BUFFER),
520       DEBUG_NAMED_VALUE(PIPE_BIND_SCANOUT),
521       DEBUG_NAMED_VALUE(PIPE_BIND_SHARED),
522       DEBUG_NAMED_VALUE(PIPE_BIND_LINEAR),
523       DEBUG_NAMED_VALUE_END
524    };
525 
526    debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
527 }
528 
529 
530 /**
531  * Print PIPE_USAGE_x enum values with a message.
532  */
533 void
debug_print_usage_enum(const char * msg,enum pipe_resource_usage usage)534 debug_print_usage_enum(const char *msg, enum pipe_resource_usage usage)
535 {
536    static const struct debug_named_value names[] = {
537       DEBUG_NAMED_VALUE(PIPE_USAGE_DEFAULT),
538       DEBUG_NAMED_VALUE(PIPE_USAGE_IMMUTABLE),
539       DEBUG_NAMED_VALUE(PIPE_USAGE_DYNAMIC),
540       DEBUG_NAMED_VALUE(PIPE_USAGE_STREAM),
541       DEBUG_NAMED_VALUE(PIPE_USAGE_STAGING),
542       DEBUG_NAMED_VALUE_END
543    };
544 
545    debug_printf("%s: %s\n", msg, debug_dump_enum(names, usage));
546 }
547 
548 
549 #endif
550