Home | History | Annotate | Download | only in util
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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_tile.h"
     42 #include "util/u_prim.h"
     43 #include "util/u_surface.h"
     44 
     45 #include <stdio.h>
     46 #include <limits.h> /* CHAR_BIT */
     47 #include <ctype.h> /* isalnum */
     48 
     49 void _debug_vprintf(const char *format, va_list ap)
     50 {
     51    static char buf[4096] = {'\0'};
     52 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
     53    /* We buffer until we find a newline. */
     54    size_t len = strlen(buf);
     55    int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
     56    if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
     57       os_log_message(buf);
     58       buf[0] = '\0';
     59    }
     60 #else
     61    util_vsnprintf(buf, sizeof(buf), format, ap);
     62    os_log_message(buf);
     63 #endif
     64 }
     65 
     66 
     67 #ifdef DEBUG
     68 void debug_print_blob( const char *name,
     69                        const void *blob,
     70                        unsigned size )
     71 {
     72    const unsigned *ublob = (const unsigned *)blob;
     73    unsigned i;
     74 
     75    debug_printf("%s (%d dwords%s)\n", name, size/4,
     76                 size%4 ? "... plus a few bytes" : "");
     77 
     78    for (i = 0; i < size/4; i++) {
     79       debug_printf("%d:\t%08x\n", i, ublob[i]);
     80    }
     81 }
     82 #endif
     83 
     84 
     85 static boolean
     86 debug_get_option_should_print(void)
     87 {
     88    static boolean first = TRUE;
     89    static boolean value = FALSE;
     90 
     91    if (!first)
     92       return value;
     93 
     94    /* Oh hey this will call into this function,
     95     * but its cool since we set first to false
     96     */
     97    first = FALSE;
     98    value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
     99    /* XXX should we print this option? Currently it wont */
    100    return value;
    101 }
    102 
    103 const char *
    104 debug_get_option(const char *name, const char *dfault)
    105 {
    106    const char *result;
    107 
    108    result = os_get_option(name);
    109    if(!result)
    110       result = dfault;
    111 
    112    if (debug_get_option_should_print())
    113       debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
    114 
    115    return result;
    116 }
    117 
    118 boolean
    119 debug_get_bool_option(const char *name, boolean dfault)
    120 {
    121    const char *str = os_get_option(name);
    122    boolean result;
    123 
    124    if(str == NULL)
    125       result = dfault;
    126    else if(!util_strcmp(str, "n"))
    127       result = FALSE;
    128    else if(!util_strcmp(str, "no"))
    129       result = FALSE;
    130    else if(!util_strcmp(str, "0"))
    131       result = FALSE;
    132    else if(!util_strcmp(str, "f"))
    133       result = FALSE;
    134    else if(!util_strcmp(str, "F"))
    135       result = FALSE;
    136    else if(!util_strcmp(str, "false"))
    137       result = FALSE;
    138    else if(!util_strcmp(str, "FALSE"))
    139       result = FALSE;
    140    else
    141       result = TRUE;
    142 
    143    if (debug_get_option_should_print())
    144       debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
    145 
    146    return result;
    147 }
    148 
    149 
    150 long
    151 debug_get_num_option(const char *name, long dfault)
    152 {
    153    long result;
    154    const char *str;
    155 
    156    str = os_get_option(name);
    157    if(!str)
    158       result = dfault;
    159    else {
    160       long sign;
    161       char c;
    162       c = *str++;
    163       if(c == '-') {
    164 	 sign = -1;
    165 	 c = *str++;
    166       }
    167       else {
    168 	 sign = 1;
    169       }
    170       result = 0;
    171       while('0' <= c && c <= '9') {
    172 	 result = result*10 + (c - '0');
    173 	 c = *str++;
    174       }
    175       result *= sign;
    176    }
    177 
    178    if (debug_get_option_should_print())
    179       debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
    180 
    181    return result;
    182 }
    183 
    184 static boolean str_has_option(const char *str, const char *name)
    185 {
    186    /* Empty string. */
    187    if (!*str) {
    188       return FALSE;
    189    }
    190 
    191    /* OPTION=all */
    192    if (!util_strcmp(str, "all")) {
    193       return TRUE;
    194    }
    195 
    196    /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
    197    {
    198       const char *start = str;
    199       unsigned name_len = strlen(name);
    200 
    201       /* 'start' is the beginning of the currently-parsed word,
    202        * we increment 'str' each iteration.
    203        * if we find either the end of string or a non-alphanumeric character,
    204        * we compare 'start' up to 'str-1' with 'name'. */
    205 
    206       while (1) {
    207          if (!*str || !(isalnum(*str) || *str == '_')) {
    208             if (str-start == name_len &&
    209                 !memcmp(start, name, name_len)) {
    210                return TRUE;
    211             }
    212 
    213             if (!*str) {
    214                return FALSE;
    215             }
    216 
    217             start = str+1;
    218          }
    219 
    220          str++;
    221       }
    222    }
    223 
    224    return FALSE;
    225 }
    226 
    227 unsigned long
    228 debug_get_flags_option(const char *name,
    229                        const struct debug_named_value *flags,
    230                        unsigned long dfault)
    231 {
    232    unsigned long result;
    233    const char *str;
    234    const struct debug_named_value *orig = flags;
    235    int namealign = 0;
    236 
    237    str = os_get_option(name);
    238    if(!str)
    239       result = dfault;
    240    else if (!util_strcmp(str, "help")) {
    241       result = dfault;
    242       _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
    243       for (; flags->name; ++flags)
    244          namealign = MAX2(namealign, strlen(flags->name));
    245       for (flags = orig; flags->name; ++flags)
    246          _debug_printf("| %*s [0x%0*lx]%s%s\n", namealign, flags->name,
    247                       (int)sizeof(unsigned long)*CHAR_BIT/4, flags->value,
    248                       flags->desc ? " " : "", flags->desc ? flags->desc : "");
    249    }
    250    else {
    251       result = 0;
    252       while( flags->name ) {
    253 	 if (str_has_option(str, flags->name))
    254 	    result |= flags->value;
    255 	 ++flags;
    256       }
    257    }
    258 
    259    if (debug_get_option_should_print()) {
    260       if (str) {
    261          debug_printf("%s: %s = 0x%lx (%s)\n", __FUNCTION__, name, result, str);
    262       } else {
    263          debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
    264       }
    265    }
    266 
    267    return result;
    268 }
    269 
    270 
    271 void _debug_assert_fail(const char *expr,
    272                         const char *file,
    273                         unsigned line,
    274                         const char *function)
    275 {
    276    _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
    277    if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", TRUE))
    278       os_abort();
    279    else
    280       _debug_printf("continuing...\n");
    281 }
    282 
    283 
    284 const char *
    285 debug_dump_enum(const struct debug_named_value *names,
    286                 unsigned long value)
    287 {
    288    static char rest[64];
    289 
    290    while(names->name) {
    291       if(names->value == value)
    292 	 return names->name;
    293       ++names;
    294    }
    295 
    296    util_snprintf(rest, sizeof(rest), "0x%08lx", value);
    297    return rest;
    298 }
    299 
    300 
    301 const char *
    302 debug_dump_enum_noprefix(const struct debug_named_value *names,
    303                          const char *prefix,
    304                          unsigned long value)
    305 {
    306    static char rest[64];
    307 
    308    while(names->name) {
    309       if(names->value == value) {
    310          const char *name = names->name;
    311          while (*name == *prefix) {
    312             name++;
    313             prefix++;
    314          }
    315          return name;
    316       }
    317       ++names;
    318    }
    319 
    320 
    321 
    322    util_snprintf(rest, sizeof(rest), "0x%08lx", value);
    323    return rest;
    324 }
    325 
    326 
    327 const char *
    328 debug_dump_flags(const struct debug_named_value *names,
    329                  unsigned long value)
    330 {
    331    static char output[4096];
    332    static char rest[256];
    333    int first = 1;
    334 
    335    output[0] = '\0';
    336 
    337    while(names->name) {
    338       if((names->value & value) == names->value) {
    339 	 if (!first)
    340 	    util_strncat(output, "|", sizeof(output));
    341 	 else
    342 	    first = 0;
    343 	 util_strncat(output, names->name, sizeof(output) - 1);
    344 	 output[sizeof(output) - 1] = '\0';
    345 	 value &= ~names->value;
    346       }
    347       ++names;
    348    }
    349 
    350    if (value) {
    351       if (!first)
    352 	 util_strncat(output, "|", sizeof(output));
    353       else
    354 	 first = 0;
    355 
    356       util_snprintf(rest, sizeof(rest), "0x%08lx", value);
    357       util_strncat(output, rest, sizeof(output) - 1);
    358       output[sizeof(output) - 1] = '\0';
    359    }
    360 
    361    if(first)
    362       return "0";
    363 
    364    return output;
    365 }
    366 
    367 
    368 #ifdef DEBUG
    369 void debug_print_format(const char *msg, unsigned fmt )
    370 {
    371    debug_printf("%s: %s\n", msg, util_format_name(fmt));
    372 }
    373 #endif
    374 
    375 
    376 
    377 static const struct debug_named_value pipe_prim_names[] = {
    378 #ifdef DEBUG
    379    DEBUG_NAMED_VALUE(PIPE_PRIM_POINTS),
    380    DEBUG_NAMED_VALUE(PIPE_PRIM_LINES),
    381    DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_LOOP),
    382    DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP),
    383    DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES),
    384    DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP),
    385    DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_FAN),
    386    DEBUG_NAMED_VALUE(PIPE_PRIM_QUADS),
    387    DEBUG_NAMED_VALUE(PIPE_PRIM_QUAD_STRIP),
    388    DEBUG_NAMED_VALUE(PIPE_PRIM_POLYGON),
    389 #endif
    390    DEBUG_NAMED_VALUE_END
    391 };
    392 
    393 
    394 const char *u_prim_name( unsigned prim )
    395 {
    396    return debug_dump_enum(pipe_prim_names, prim);
    397 }
    398 
    399 
    400 
    401 #ifdef DEBUG
    402 int fl_indent = 0;
    403 const char* fl_function[1024];
    404 
    405 int debug_funclog_enter(const char* f, const int line, const char* file)
    406 {
    407    int i;
    408 
    409    for (i = 0; i < fl_indent; i++)
    410       debug_printf("  ");
    411    debug_printf("%s\n", f);
    412 
    413    assert(fl_indent < 1023);
    414    fl_function[fl_indent++] = f;
    415 
    416    return 0;
    417 }
    418 
    419 void debug_funclog_exit(const char* f, const int line, const char* file)
    420 {
    421    --fl_indent;
    422    assert(fl_indent >= 0);
    423    assert(fl_function[fl_indent] == f);
    424 }
    425 
    426 void debug_funclog_enter_exit(const char* f, const int line, const char* file)
    427 {
    428    int i;
    429    for (i = 0; i < fl_indent; i++)
    430       debug_printf("  ");
    431    debug_printf("%s\n", f);
    432 }
    433 #endif
    434 
    435 
    436 
    437 #ifdef DEBUG
    438 /**
    439  * Dump an image to a .raw or .ppm file (depends on OS).
    440  * \param format  PIPE_FORMAT_x
    441  * \param cpp  bytes per pixel
    442  * \param width  width in pixels
    443  * \param height height in pixels
    444  * \param stride  row stride in bytes
    445  */
    446 void debug_dump_image(const char *prefix,
    447                       unsigned format, unsigned cpp,
    448                       unsigned width, unsigned height,
    449                       unsigned stride,
    450                       const void *data)
    451 {
    452    /* write a ppm file */
    453    char filename[256];
    454    FILE *f;
    455 
    456    util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
    457 
    458    f = fopen(filename, "w");
    459    if (f) {
    460       int i, x, y;
    461       int r, g, b;
    462       const uint8_t *ptr = (uint8_t *) data;
    463 
    464       /* XXX this is a hack */
    465       switch (format) {
    466       case PIPE_FORMAT_B8G8R8A8_UNORM:
    467          r = 2;
    468          g = 1;
    469          b = 0;
    470          break;
    471       default:
    472          r = 0;
    473          g = 1;
    474          b = 1;
    475       }
    476 
    477       fprintf(f, "P6\n");
    478       fprintf(f, "# ppm-file created by osdemo.c\n");
    479       fprintf(f, "%i %i\n", width, height);
    480       fprintf(f, "255\n");
    481       fclose(f);
    482 
    483       f = fopen(filename, "ab");  /* reopen in binary append mode */
    484       for (y = 0; y < height; y++) {
    485          for (x = 0; x < width; x++) {
    486             i = y * stride + x * cpp;
    487             fputc(ptr[i + r], f); /* write red */
    488             fputc(ptr[i + g], f); /* write green */
    489             fputc(ptr[i + b], f); /* write blue */
    490          }
    491       }
    492       fclose(f);
    493    }
    494    else {
    495       fprintf(stderr, "Can't open %s for writing\n", filename);
    496    }
    497 }
    498 
    499 /* FIXME: dump resources, not surfaces... */
    500 void debug_dump_surface(struct pipe_context *pipe,
    501                         const char *prefix,
    502                         struct pipe_surface *surface)
    503 {
    504    struct pipe_resource *texture;
    505    struct pipe_transfer *transfer;
    506    void *data;
    507 
    508    if (!surface)
    509       return;
    510 
    511    /* XXX: this doesn't necessarily work, as the driver may be using
    512     * temporary storage for the surface which hasn't been propagated
    513     * back into the texture.  Need to nail down the semantics of views
    514     * and transfers a bit better before we can say if extra work needs
    515     * to be done here:
    516     */
    517    texture = surface->texture;
    518 
    519    transfer = pipe_get_transfer(pipe, texture, surface->u.tex.level,
    520                                 surface->u.tex.first_layer,
    521                                 PIPE_TRANSFER_READ,
    522                                 0, 0, surface->width, surface->height);
    523 
    524    data = pipe->transfer_map(pipe, transfer);
    525    if(!data)
    526       goto error;
    527 
    528    debug_dump_image(prefix,
    529                     texture->format,
    530                     util_format_get_blocksize(texture->format),
    531                     util_format_get_nblocksx(texture->format, surface->width),
    532                     util_format_get_nblocksy(texture->format, surface->height),
    533                     transfer->stride,
    534                     data);
    535 
    536    pipe->transfer_unmap(pipe, transfer);
    537 error:
    538    pipe->transfer_destroy(pipe, transfer);
    539 }
    540 
    541 
    542 void debug_dump_texture(struct pipe_context *pipe,
    543                         const char *prefix,
    544                         struct pipe_resource *texture)
    545 {
    546    struct pipe_surface *surface, surf_tmpl;
    547 
    548    if (!texture)
    549       return;
    550 
    551    /* XXX for now, just dump image for layer=0, level=0 */
    552    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
    553    u_surface_default_template(&surf_tmpl, texture, 0 /* no bind flag - not a surface */);
    554    surface = pipe->create_surface(pipe, texture, &surf_tmpl);
    555    if (surface) {
    556       debug_dump_surface(pipe, prefix, surface);
    557       pipe->surface_destroy(pipe, surface);
    558    }
    559 }
    560 
    561 
    562 #pragma pack(push,2)
    563 struct bmp_file_header {
    564    uint16_t bfType;
    565    uint32_t bfSize;
    566    uint16_t bfReserved1;
    567    uint16_t bfReserved2;
    568    uint32_t bfOffBits;
    569 };
    570 #pragma pack(pop)
    571 
    572 struct bmp_info_header {
    573    uint32_t biSize;
    574    int32_t biWidth;
    575    int32_t biHeight;
    576    uint16_t biPlanes;
    577    uint16_t biBitCount;
    578    uint32_t biCompression;
    579    uint32_t biSizeImage;
    580    int32_t biXPelsPerMeter;
    581    int32_t biYPelsPerMeter;
    582    uint32_t biClrUsed;
    583    uint32_t biClrImportant;
    584 };
    585 
    586 struct bmp_rgb_quad {
    587    uint8_t rgbBlue;
    588    uint8_t rgbGreen;
    589    uint8_t rgbRed;
    590    uint8_t rgbAlpha;
    591 };
    592 
    593 void
    594 debug_dump_surface_bmp(struct pipe_context *pipe,
    595                        const char *filename,
    596                        struct pipe_surface *surface)
    597 {
    598    struct pipe_transfer *transfer;
    599    struct pipe_resource *texture = surface->texture;
    600 
    601    transfer = pipe_get_transfer(pipe, texture, surface->u.tex.level,
    602                                 surface->u.tex.first_layer, PIPE_TRANSFER_READ,
    603                                 0, 0, surface->width, surface->height);
    604 
    605    debug_dump_transfer_bmp(pipe, filename, transfer);
    606 
    607    pipe->transfer_destroy(pipe, transfer);
    608 }
    609 
    610 void
    611 debug_dump_transfer_bmp(struct pipe_context *pipe,
    612                         const char *filename,
    613                         struct pipe_transfer *transfer)
    614 {
    615    float *rgba;
    616 
    617    if (!transfer)
    618       goto error1;
    619 
    620    rgba = MALLOC(transfer->box.width *
    621 		 transfer->box.height *
    622 		 transfer->box.depth *
    623 		 4*sizeof(float));
    624    if(!rgba)
    625       goto error1;
    626 
    627    pipe_get_tile_rgba(pipe, transfer, 0, 0,
    628                       transfer->box.width, transfer->box.height,
    629                       rgba);
    630 
    631    debug_dump_float_rgba_bmp(filename,
    632                              transfer->box.width, transfer->box.height,
    633                              rgba, transfer->box.width);
    634 
    635    FREE(rgba);
    636 error1:
    637    ;
    638 }
    639 
    640 void
    641 debug_dump_float_rgba_bmp(const char *filename,
    642                           unsigned width, unsigned height,
    643                           float *rgba, unsigned stride)
    644 {
    645    FILE *stream;
    646    struct bmp_file_header bmfh;
    647    struct bmp_info_header bmih;
    648    unsigned x, y;
    649 
    650    if(!rgba)
    651       goto error1;
    652 
    653    bmfh.bfType = 0x4d42;
    654    bmfh.bfSize = 14 + 40 + height*width*4;
    655    bmfh.bfReserved1 = 0;
    656    bmfh.bfReserved2 = 0;
    657    bmfh.bfOffBits = 14 + 40;
    658 
    659    bmih.biSize = 40;
    660    bmih.biWidth = width;
    661    bmih.biHeight = height;
    662    bmih.biPlanes = 1;
    663    bmih.biBitCount = 32;
    664    bmih.biCompression = 0;
    665    bmih.biSizeImage = height*width*4;
    666    bmih.biXPelsPerMeter = 0;
    667    bmih.biYPelsPerMeter = 0;
    668    bmih.biClrUsed = 0;
    669    bmih.biClrImportant = 0;
    670 
    671    stream = fopen(filename, "wb");
    672    if(!stream)
    673       goto error1;
    674 
    675    fwrite(&bmfh, 14, 1, stream);
    676    fwrite(&bmih, 40, 1, stream);
    677 
    678    y = height;
    679    while(y--) {
    680       float *ptr = rgba + (stride * y * 4);
    681       for(x = 0; x < width; ++x)
    682       {
    683          struct bmp_rgb_quad pixel;
    684          pixel.rgbRed   = float_to_ubyte(ptr[x*4 + 0]);
    685          pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
    686          pixel.rgbBlue  = float_to_ubyte(ptr[x*4 + 2]);
    687          pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]);
    688          fwrite(&pixel, 1, 4, stream);
    689       }
    690    }
    691 
    692    fclose(stream);
    693 error1:
    694    ;
    695 }
    696 
    697 #endif
    698