Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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_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. #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. {
  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. debug_disable_error_message_boxes(void)
  75. {
  76. #ifdef _WIN32
  77.    /* When Windows' error message boxes are disabled for this process (as is
  78.     * typically the case when running tests in an automated fashion) we disable
  79.     * CRT message boxes too.
  80.     */
  81.    UINT uMode = SetErrorMode(0);
  82.    SetErrorMode(uMode);
  83.    if (uMode & SEM_FAILCRITICALERRORS) {
  84.       /* Disable assertion failure message box.
  85.        * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
  86.        */
  87.       _set_error_mode(_OUT_TO_STDERR);
  88. #ifdef _MSC_VER
  89.       /* Disable abort message box.
  90.        * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
  91.        */
  92.       _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  93. #endif
  94.    }
  95. #endif /* _WIN32 */
  96. }
  97.  
  98.  
  99. #ifdef DEBUG
  100. void debug_print_blob( const char *name,
  101.                        const void *blob,
  102.                        unsigned size )
  103. {
  104.    const unsigned *ublob = (const unsigned *)blob;
  105.    unsigned i;
  106.  
  107.    debug_printf("%s (%d dwords%s)\n", name, size/4,
  108.                 size%4 ? "... plus a few bytes" : "");
  109.  
  110.    for (i = 0; i < size/4; i++) {
  111.       debug_printf("%d:\t%08x\n", i, ublob[i]);
  112.    }
  113. }
  114. #endif
  115.  
  116.  
  117. static boolean
  118. debug_get_option_should_print(void)
  119. {
  120.    static boolean first = TRUE;
  121.    static boolean value = FALSE;
  122.  
  123.    if (!first)
  124.       return value;
  125.  
  126.    /* Oh hey this will call into this function,
  127.     * but its cool since we set first to false
  128.     */
  129.    first = FALSE;
  130.    value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
  131.    /* XXX should we print this option? Currently it wont */
  132.    return value;
  133. }
  134.  
  135. const char *
  136. debug_get_option(const char *name, const char *dfault)
  137. {
  138.    const char *result;
  139.  
  140.    result = os_get_option(name);
  141.    if(!result)
  142.       result = dfault;
  143.  
  144.    if (debug_get_option_should_print())
  145.       debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
  146.    
  147.    return result;
  148. }
  149.  
  150. boolean
  151. debug_get_bool_option(const char *name, boolean dfault)
  152. {
  153.    const char *str = os_get_option(name);
  154.    boolean result;
  155.    
  156.    if(str == NULL)
  157.       result = dfault;
  158.    else if(!util_strcmp(str, "n"))
  159.       result = FALSE;
  160.    else if(!util_strcmp(str, "no"))
  161.       result = FALSE;
  162.    else if(!util_strcmp(str, "0"))
  163.       result = FALSE;
  164.    else if(!util_strcmp(str, "f"))
  165.       result = FALSE;
  166.    else if(!util_strcmp(str, "F"))
  167.       result = FALSE;
  168.    else if(!util_strcmp(str, "false"))
  169.       result = FALSE;
  170.    else if(!util_strcmp(str, "FALSE"))
  171.       result = FALSE;
  172.    else
  173.       result = TRUE;
  174.  
  175.    if (debug_get_option_should_print())
  176.       debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
  177.    
  178.    return result;
  179. }
  180.  
  181.  
  182. long
  183. debug_get_num_option(const char *name, long dfault)
  184. {
  185.    long result;
  186.    const char *str;
  187.    
  188.    str = os_get_option(name);
  189.    if(!str)
  190.       result = dfault;
  191.    else {
  192.       long sign;
  193.       char c;
  194.       c = *str++;
  195.       if(c == '-') {
  196.          sign = -1;
  197.          c = *str++;
  198.       }
  199.       else {
  200.          sign = 1;
  201.       }
  202.       result = 0;
  203.       while('0' <= c && c <= '9') {
  204.          result = result*10 + (c - '0');
  205.          c = *str++;
  206.       }
  207.       result *= sign;
  208.    }
  209.  
  210.    if (debug_get_option_should_print())
  211.       debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
  212.  
  213.    return result;
  214. }
  215.  
  216. static boolean str_has_option(const char *str, const char *name)
  217. {
  218.    /* Empty string. */
  219.    if (!*str) {
  220.       return FALSE;
  221.    }
  222.  
  223.    /* OPTION=all */
  224.    if (!util_strcmp(str, "all")) {
  225.       return TRUE;
  226.    }
  227.  
  228.    /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
  229.    {
  230.       const char *start = str;
  231.       unsigned name_len = strlen(name);
  232.  
  233.       /* 'start' is the beginning of the currently-parsed word,
  234.        * we increment 'str' each iteration.
  235.        * if we find either the end of string or a non-alphanumeric character,
  236.        * we compare 'start' up to 'str-1' with 'name'. */
  237.  
  238.       while (1) {
  239.          if (!*str || !(isalnum(*str) || *str == '_')) {
  240.             if (str-start == name_len &&
  241.                 !memcmp(start, name, name_len)) {
  242.                return TRUE;
  243.             }
  244.  
  245.             if (!*str) {
  246.                return FALSE;
  247.             }
  248.  
  249.             start = str+1;
  250.          }
  251.  
  252.          str++;
  253.       }
  254.    }
  255.  
  256.    return FALSE;
  257. }
  258.  
  259. unsigned long
  260. debug_get_flags_option(const char *name,
  261.                        const struct debug_named_value *flags,
  262.                        unsigned long dfault)
  263. {
  264.    unsigned long result;
  265.    const char *str;
  266.    const struct debug_named_value *orig = flags;
  267.    unsigned namealign = 0;
  268.    
  269.    str = os_get_option(name);
  270.    if(!str)
  271.       result = dfault;
  272.    else if (!util_strcmp(str, "help")) {
  273.       result = dfault;
  274.       _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
  275.       for (; flags->name; ++flags)
  276.          namealign = MAX2(namealign, strlen(flags->name));
  277.       for (flags = orig; flags->name; ++flags)
  278.          _debug_printf("| %*s [0x%0*lx]%s%s\n", namealign, flags->name,
  279.                       (int)sizeof(unsigned long)*CHAR_BIT/4, flags->value,
  280.                       flags->desc ? " " : "", flags->desc ? flags->desc : "");
  281.    }
  282.    else {
  283.       result = 0;
  284.       while( flags->name ) {
  285.          if (str_has_option(str, flags->name))
  286.             result |= flags->value;
  287.          ++flags;
  288.       }
  289.    }
  290.  
  291.    if (debug_get_option_should_print()) {
  292.       if (str) {
  293.          debug_printf("%s: %s = 0x%lx (%s)\n", __FUNCTION__, name, result, str);
  294.       } else {
  295.          debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
  296.       }
  297.    }
  298.  
  299.    return result;
  300. }
  301.  
  302.  
  303. void _debug_assert_fail(const char *expr,
  304.                         const char *file,
  305.                         unsigned line,
  306.                         const char *function)
  307. {
  308.    _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
  309.    os_abort();
  310. }
  311.  
  312.  
  313. const char *
  314. debug_dump_enum(const struct debug_named_value *names,
  315.                 unsigned long value)
  316. {
  317.    static char rest[64];
  318.    
  319.    while(names->name) {
  320.       if(names->value == value)
  321.          return names->name;
  322.       ++names;
  323.    }
  324.  
  325.    util_snprintf(rest, sizeof(rest), "0x%08lx", value);
  326.    return rest;
  327. }
  328.  
  329.  
  330. const char *
  331. debug_dump_enum_noprefix(const struct debug_named_value *names,
  332.                          const char *prefix,
  333.                          unsigned long value)
  334. {
  335.    static char rest[64];
  336.    
  337.    while(names->name) {
  338.       if(names->value == value) {
  339.          const char *name = names->name;
  340.          while (*name == *prefix) {
  341.             name++;
  342.             prefix++;
  343.          }
  344.          return name;
  345.       }
  346.       ++names;
  347.    }
  348.  
  349.    
  350.  
  351.    util_snprintf(rest, sizeof(rest), "0x%08lx", value);
  352.    return rest;
  353. }
  354.  
  355.  
  356. const char *
  357. debug_dump_flags(const struct debug_named_value *names,
  358.                  unsigned long value)
  359. {
  360.    static char output[4096];
  361.    static char rest[256];
  362.    int first = 1;
  363.  
  364.    output[0] = '\0';
  365.  
  366.    while(names->name) {
  367.       if((names->value & value) == names->value) {
  368.          if (!first)
  369.             util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
  370.          else
  371.             first = 0;
  372.          util_strncat(output, names->name, sizeof(output) - strlen(output) - 1);
  373.          output[sizeof(output) - 1] = '\0';
  374.          value &= ~names->value;
  375.       }
  376.       ++names;
  377.    }
  378.    
  379.    if (value) {
  380.       if (!first)
  381.          util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
  382.       else
  383.          first = 0;
  384.      
  385.       util_snprintf(rest, sizeof(rest), "0x%08lx", value);
  386.       util_strncat(output, rest, sizeof(output) - strlen(output) - 1);
  387.       output[sizeof(output) - 1] = '\0';
  388.    }
  389.    
  390.    if(first)
  391.       return "0";
  392.    
  393.    return output;
  394. }
  395.  
  396.  
  397. #ifdef DEBUG
  398. void debug_print_format(const char *msg, unsigned fmt )
  399. {
  400.    debug_printf("%s: %s\n", msg, util_format_name(fmt));
  401. }
  402. #endif
  403.  
  404.  
  405. /** Return string name of given primitive type */
  406. const char *
  407. u_prim_name(unsigned prim)
  408. {
  409.    static const struct debug_named_value names[] = {
  410.       DEBUG_NAMED_VALUE(PIPE_PRIM_POINTS),
  411.       DEBUG_NAMED_VALUE(PIPE_PRIM_LINES),
  412.       DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_LOOP),
  413.       DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP),
  414.       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES),
  415.       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP),
  416.       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_FAN),
  417.       DEBUG_NAMED_VALUE(PIPE_PRIM_QUADS),
  418.       DEBUG_NAMED_VALUE(PIPE_PRIM_QUAD_STRIP),
  419.       DEBUG_NAMED_VALUE(PIPE_PRIM_POLYGON),
  420.       DEBUG_NAMED_VALUE(PIPE_PRIM_LINES_ADJACENCY),
  421.       DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP_ADJACENCY),
  422.       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES_ADJACENCY),
  423.       DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY),
  424.       DEBUG_NAMED_VALUE_END
  425.    };
  426.    return debug_dump_enum(names, prim);
  427. }
  428.  
  429.  
  430.  
  431. #ifdef DEBUG
  432. int fl_indent = 0;
  433. const char* fl_function[1024];
  434.  
  435. int debug_funclog_enter(const char* f, const int line, const char* file)
  436. {
  437.    int i;
  438.  
  439.    for (i = 0; i < fl_indent; i++)
  440.       debug_printf("  ");
  441.    debug_printf("%s\n", f);
  442.  
  443.    assert(fl_indent < 1023);
  444.    fl_function[fl_indent++] = f;
  445.  
  446.    return 0;
  447. }
  448.  
  449. void debug_funclog_exit(const char* f, const int line, const char* file)
  450. {
  451.    --fl_indent;
  452.    assert(fl_indent >= 0);
  453.    assert(fl_function[fl_indent] == f);
  454. }
  455.  
  456. void debug_funclog_enter_exit(const char* f, const int line, const char* file)
  457. {
  458.    int i;
  459.    for (i = 0; i < fl_indent; i++)
  460.       debug_printf("  ");
  461.    debug_printf("%s\n", f);
  462. }
  463. #endif
  464.  
  465.  
  466.  
  467. #ifdef DEBUG
  468. /**
  469.  * Dump an image to .ppm file.
  470.  * \param format  PIPE_FORMAT_x
  471.  * \param cpp  bytes per pixel
  472.  * \param width  width in pixels
  473.  * \param height height in pixels
  474.  * \param stride  row stride in bytes
  475.  */
  476. void debug_dump_image(const char *prefix,
  477.                       enum pipe_format format, unsigned cpp,
  478.                       unsigned width, unsigned height,
  479.                       unsigned stride,
  480.                       const void *data)    
  481. {
  482.    /* write a ppm file */
  483.    char filename[256];
  484.    unsigned char *rgb8;
  485.    FILE *f;
  486.  
  487.    util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
  488.  
  489.    rgb8 = MALLOC(height * width * 3);
  490.    if (!rgb8) {
  491.       return;
  492.    }
  493.  
  494.    util_format_translate(
  495.          PIPE_FORMAT_R8G8B8_UNORM,
  496.          rgb8, width * 3,
  497.          0, 0,
  498.          format,
  499.          data, stride,
  500.          0, 0, width, height);
  501.  
  502.    /* Must be opened in binary mode or DOS line ending causes data
  503.     * to be read with one byte offset.
  504.     */
  505.    f = fopen(filename, "wb");
  506.    if (f) {
  507.       fprintf(f, "P6\n");
  508.       fprintf(f, "# ppm-file created by gallium\n");
  509.       fprintf(f, "%i %i\n", width, height);
  510.       fprintf(f, "255\n");
  511.       fwrite(rgb8, 1, height * width * 3, f);
  512.       fclose(f);
  513.    }
  514.    else {
  515.       fprintf(stderr, "Can't open %s for writing\n", filename);
  516.    }
  517.  
  518.    FREE(rgb8);
  519. }
  520.  
  521. /* FIXME: dump resources, not surfaces... */
  522. void debug_dump_surface(struct pipe_context *pipe,
  523.                         const char *prefix,
  524.                         struct pipe_surface *surface)
  525. {
  526.    struct pipe_resource *texture;
  527.    struct pipe_transfer *transfer;
  528.    void *data;
  529.  
  530.    if (!surface)
  531.       return;
  532.  
  533.    /* XXX: this doesn't necessarily work, as the driver may be using
  534.     * temporary storage for the surface which hasn't been propagated
  535.     * back into the texture.  Need to nail down the semantics of views
  536.     * and transfers a bit better before we can say if extra work needs
  537.     * to be done here:
  538.     */
  539.    texture = surface->texture;
  540.  
  541.    data = pipe_transfer_map(pipe, texture, surface->u.tex.level,
  542.                             surface->u.tex.first_layer,
  543.                             PIPE_TRANSFER_READ,
  544.                             0, 0, surface->width, surface->height, &transfer);
  545.    if(!data)
  546.       return;
  547.  
  548.    debug_dump_image(prefix,
  549.                     texture->format,
  550.                     util_format_get_blocksize(texture->format),
  551.                     util_format_get_nblocksx(texture->format, surface->width),
  552.                     util_format_get_nblocksy(texture->format, surface->height),
  553.                     transfer->stride,
  554.                     data);
  555.  
  556.    pipe->transfer_unmap(pipe, transfer);
  557. }
  558.  
  559.  
  560. void debug_dump_texture(struct pipe_context *pipe,
  561.                         const char *prefix,
  562.                         struct pipe_resource *texture)
  563. {
  564.    struct pipe_surface *surface, surf_tmpl;
  565.  
  566.    if (!texture)
  567.       return;
  568.  
  569.    /* XXX for now, just dump image for layer=0, level=0 */
  570.    u_surface_default_template(&surf_tmpl, texture);
  571.    surface = pipe->create_surface(pipe, texture, &surf_tmpl);
  572.    if (surface) {
  573.       debug_dump_surface(pipe, prefix, surface);
  574.       pipe->surface_destroy(pipe, surface);
  575.    }
  576. }
  577.  
  578.  
  579. #pragma pack(push,2)
  580. struct bmp_file_header {
  581.    uint16_t bfType;
  582.    uint32_t bfSize;
  583.    uint16_t bfReserved1;
  584.    uint16_t bfReserved2;
  585.    uint32_t bfOffBits;
  586. };
  587. #pragma pack(pop)
  588.  
  589. struct bmp_info_header {
  590.    uint32_t biSize;
  591.    int32_t biWidth;
  592.    int32_t biHeight;
  593.    uint16_t biPlanes;
  594.    uint16_t biBitCount;
  595.    uint32_t biCompression;
  596.    uint32_t biSizeImage;
  597.    int32_t biXPelsPerMeter;
  598.    int32_t biYPelsPerMeter;
  599.    uint32_t biClrUsed;
  600.    uint32_t biClrImportant;
  601. };
  602.  
  603. struct bmp_rgb_quad {
  604.    uint8_t rgbBlue;
  605.    uint8_t rgbGreen;
  606.    uint8_t rgbRed;
  607.    uint8_t rgbAlpha;
  608. };
  609.  
  610. void
  611. debug_dump_surface_bmp(struct pipe_context *pipe,
  612.                        const char *filename,
  613.                        struct pipe_surface *surface)
  614. {
  615.    struct pipe_transfer *transfer;
  616.    struct pipe_resource *texture = surface->texture;
  617.    void *ptr;
  618.  
  619.    ptr = pipe_transfer_map(pipe, texture, surface->u.tex.level,
  620.                            surface->u.tex.first_layer, PIPE_TRANSFER_READ,
  621.                            0, 0, surface->width, surface->height, &transfer);
  622.  
  623.    debug_dump_transfer_bmp(pipe, filename, transfer, ptr);
  624.  
  625.    pipe->transfer_unmap(pipe, transfer);
  626. }
  627.  
  628. void
  629. debug_dump_transfer_bmp(struct pipe_context *pipe,
  630.                         const char *filename,
  631.                         struct pipe_transfer *transfer, void *ptr)
  632. {
  633.    float *rgba;
  634.  
  635.    if (!transfer)
  636.       goto error1;
  637.  
  638.    rgba = MALLOC(transfer->box.width *
  639.                  transfer->box.height *
  640.                  transfer->box.depth *
  641.                  4*sizeof(float));
  642.    if(!rgba)
  643.       goto error1;
  644.  
  645.    pipe_get_tile_rgba(transfer, ptr, 0, 0,
  646.                       transfer->box.width, transfer->box.height,
  647.                       rgba);
  648.  
  649.    debug_dump_float_rgba_bmp(filename,
  650.                              transfer->box.width, transfer->box.height,
  651.                              rgba, transfer->box.width);
  652.  
  653.    FREE(rgba);
  654. error1:
  655.    ;
  656. }
  657.  
  658. void
  659. debug_dump_float_rgba_bmp(const char *filename,
  660.                           unsigned width, unsigned height,
  661.                           float *rgba, unsigned stride)
  662. {
  663.    FILE *stream;
  664.    struct bmp_file_header bmfh;
  665.    struct bmp_info_header bmih;
  666.    unsigned x, y;
  667.  
  668.    if(!rgba)
  669.       goto error1;
  670.  
  671.    bmfh.bfType = 0x4d42;
  672.    bmfh.bfSize = 14 + 40 + height*width*4;
  673.    bmfh.bfReserved1 = 0;
  674.    bmfh.bfReserved2 = 0;
  675.    bmfh.bfOffBits = 14 + 40;
  676.  
  677.    bmih.biSize = 40;
  678.    bmih.biWidth = width;
  679.    bmih.biHeight = height;
  680.    bmih.biPlanes = 1;
  681.    bmih.biBitCount = 32;
  682.    bmih.biCompression = 0;
  683.    bmih.biSizeImage = height*width*4;
  684.    bmih.biXPelsPerMeter = 0;
  685.    bmih.biYPelsPerMeter = 0;
  686.    bmih.biClrUsed = 0;
  687.    bmih.biClrImportant = 0;
  688.  
  689.    stream = fopen(filename, "wb");
  690.    if(!stream)
  691.       goto error1;
  692.  
  693.    fwrite(&bmfh, 14, 1, stream);
  694.    fwrite(&bmih, 40, 1, stream);
  695.  
  696.    y = height;
  697.    while(y--) {
  698.       float *ptr = rgba + (stride * y * 4);
  699.       for(x = 0; x < width; ++x)
  700.       {
  701.          struct bmp_rgb_quad pixel;
  702.          pixel.rgbRed   = float_to_ubyte(ptr[x*4 + 0]);
  703.          pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
  704.          pixel.rgbBlue  = float_to_ubyte(ptr[x*4 + 2]);
  705.          pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]);
  706.          fwrite(&pixel, 1, 4, stream);
  707.       }
  708.    }
  709.  
  710.    fclose(stream);
  711. error1:
  712.    ;
  713. }
  714.  
  715.  
  716. /**
  717.  * Print PIPE_TRANSFER_x flags with a message.
  718.  */
  719. void
  720. debug_print_transfer_flags(const char *msg, unsigned usage)
  721. {
  722.    static const struct debug_named_value names[] = {
  723.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_READ),
  724.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_WRITE),
  725.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_MAP_DIRECTLY),
  726.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_DISCARD_RANGE),
  727.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_DONTBLOCK),
  728.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_UNSYNCHRONIZED),
  729.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_FLUSH_EXPLICIT),
  730.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE),
  731.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_PERSISTENT),
  732.       DEBUG_NAMED_VALUE(PIPE_TRANSFER_COHERENT),
  733.       DEBUG_NAMED_VALUE_END
  734.    };
  735.  
  736.    debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
  737. }
  738.  
  739.  
  740. /**
  741.  * Print PIPE_BIND_x flags with a message.
  742.  */
  743. void
  744. debug_print_bind_flags(const char *msg, unsigned usage)
  745. {
  746.    static const struct debug_named_value names[] = {
  747.       DEBUG_NAMED_VALUE(PIPE_BIND_DEPTH_STENCIL),
  748.       DEBUG_NAMED_VALUE(PIPE_BIND_RENDER_TARGET),
  749.       DEBUG_NAMED_VALUE(PIPE_BIND_BLENDABLE),
  750.       DEBUG_NAMED_VALUE(PIPE_BIND_SAMPLER_VIEW),
  751.       DEBUG_NAMED_VALUE(PIPE_BIND_VERTEX_BUFFER),
  752.       DEBUG_NAMED_VALUE(PIPE_BIND_INDEX_BUFFER),
  753.       DEBUG_NAMED_VALUE(PIPE_BIND_CONSTANT_BUFFER),
  754.       DEBUG_NAMED_VALUE(PIPE_BIND_DISPLAY_TARGET),
  755.       DEBUG_NAMED_VALUE(PIPE_BIND_TRANSFER_WRITE),
  756.       DEBUG_NAMED_VALUE(PIPE_BIND_TRANSFER_READ),
  757.       DEBUG_NAMED_VALUE(PIPE_BIND_STREAM_OUTPUT),
  758.       DEBUG_NAMED_VALUE(PIPE_BIND_CURSOR),
  759.       DEBUG_NAMED_VALUE(PIPE_BIND_CUSTOM),
  760.       DEBUG_NAMED_VALUE(PIPE_BIND_GLOBAL),
  761.       DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_RESOURCE),
  762.       DEBUG_NAMED_VALUE(PIPE_BIND_COMPUTE_RESOURCE),
  763.       DEBUG_NAMED_VALUE(PIPE_BIND_COMMAND_ARGS_BUFFER),
  764.       DEBUG_NAMED_VALUE(PIPE_BIND_SCANOUT),
  765.       DEBUG_NAMED_VALUE(PIPE_BIND_SHARED),
  766.       DEBUG_NAMED_VALUE(PIPE_BIND_LINEAR),
  767.       DEBUG_NAMED_VALUE_END
  768.    };
  769.  
  770.    debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
  771. }
  772.  
  773.  
  774. /**
  775.  * Print PIPE_USAGE_x enum values with a message.
  776.  */
  777. void
  778. debug_print_usage_enum(const char *msg, unsigned usage)
  779. {
  780.    static const struct debug_named_value names[] = {
  781.       DEBUG_NAMED_VALUE(PIPE_USAGE_DEFAULT),
  782.       DEBUG_NAMED_VALUE(PIPE_USAGE_IMMUTABLE),
  783.       DEBUG_NAMED_VALUE(PIPE_USAGE_DYNAMIC),
  784.       DEBUG_NAMED_VALUE(PIPE_USAGE_STREAM),
  785.       DEBUG_NAMED_VALUE(PIPE_USAGE_STAGING),
  786.       DEBUG_NAMED_VALUE_END
  787.    };
  788.  
  789.    debug_printf("%s: %s\n", msg, debug_dump_enum(names, usage));
  790. }
  791.  
  792.  
  793. #endif
  794.