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