Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (c) 2008-2016 VMware, Inc.
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  */
     25 
     26 
     27 #include "util/u_debug_image.h"
     28 #include "util/u_format.h"
     29 #include "util/u_inlines.h"
     30 #include "util/u_memory.h"
     31 #include "util/u_string.h"
     32 #include "util/u_surface.h"
     33 #include "util/u_tile.h"
     34 
     35 #include <stdio.h>
     36 
     37 
     38 #ifdef DEBUG
     39 
     40 /**
     41  * Dump an image to .ppm file.
     42  * \param format  PIPE_FORMAT_x
     43  * \param cpp  bytes per pixel
     44  * \param width  width in pixels
     45  * \param height height in pixels
     46  * \param stride  row stride in bytes
     47  */
     48 void
     49 debug_dump_image(const char *prefix,
     50                  enum pipe_format format, unsigned cpp,
     51                  unsigned width, unsigned height,
     52                  unsigned stride,
     53                  const void *data)
     54 {
     55    /* write a ppm file */
     56    char filename[256];
     57    unsigned char *rgb8;
     58    FILE *f;
     59 
     60    util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
     61 
     62    rgb8 = MALLOC(height * width * 3);
     63    if (!rgb8) {
     64       return;
     65    }
     66 
     67    util_format_translate(
     68          PIPE_FORMAT_R8G8B8_UNORM,
     69          rgb8, width * 3,
     70          0, 0,
     71          format,
     72          data, stride,
     73          0, 0, width, height);
     74 
     75    /* Must be opened in binary mode or DOS line ending causes data
     76     * to be read with one byte offset.
     77     */
     78    f = fopen(filename, "wb");
     79    if (f) {
     80       fprintf(f, "P6\n");
     81       fprintf(f, "# ppm-file created by gallium\n");
     82       fprintf(f, "%i %i\n", width, height);
     83       fprintf(f, "255\n");
     84       fwrite(rgb8, 1, height * width * 3, f);
     85       fclose(f);
     86    }
     87    else {
     88       fprintf(stderr, "Can't open %s for writing\n", filename);
     89    }
     90 
     91    FREE(rgb8);
     92 }
     93 
     94 
     95 /* FIXME: dump resources, not surfaces... */
     96 void
     97 debug_dump_surface(struct pipe_context *pipe,
     98                    const char *prefix,
     99                    struct pipe_surface *surface)
    100 {
    101    struct pipe_resource *texture;
    102    struct pipe_transfer *transfer;
    103    void *data;
    104 
    105    if (!surface)
    106       return;
    107 
    108    /* XXX: this doesn't necessarily work, as the driver may be using
    109     * temporary storage for the surface which hasn't been propagated
    110     * back into the texture.  Need to nail down the semantics of views
    111     * and transfers a bit better before we can say if extra work needs
    112     * to be done here:
    113     */
    114    texture = surface->texture;
    115 
    116    data = pipe_transfer_map(pipe, texture, surface->u.tex.level,
    117                             surface->u.tex.first_layer,
    118                             PIPE_TRANSFER_READ,
    119                             0, 0, surface->width, surface->height, &transfer);
    120    if (!data)
    121       return;
    122 
    123    debug_dump_image(prefix,
    124                     texture->format,
    125                     util_format_get_blocksize(texture->format),
    126                     util_format_get_nblocksx(texture->format, surface->width),
    127                     util_format_get_nblocksy(texture->format, surface->height),
    128                     transfer->stride,
    129                     data);
    130 
    131    pipe->transfer_unmap(pipe, transfer);
    132 }
    133 
    134 
    135 void
    136 debug_dump_texture(struct pipe_context *pipe,
    137                    const char *prefix,
    138                    struct pipe_resource *texture)
    139 {
    140    struct pipe_surface *surface, surf_tmpl;
    141 
    142    if (!texture)
    143       return;
    144 
    145    /* XXX for now, just dump image for layer=0, level=0 */
    146    u_surface_default_template(&surf_tmpl, texture);
    147    surface = pipe->create_surface(pipe, texture, &surf_tmpl);
    148    if (surface) {
    149       debug_dump_surface(pipe, prefix, surface);
    150       pipe->surface_destroy(pipe, surface);
    151    }
    152 }
    153 
    154 
    155 #pragma pack(push,2)
    156 struct bmp_file_header {
    157    uint16_t bfType;
    158    uint32_t bfSize;
    159    uint16_t bfReserved1;
    160    uint16_t bfReserved2;
    161    uint32_t bfOffBits;
    162 };
    163 #pragma pack(pop)
    164 
    165 struct bmp_info_header {
    166    uint32_t biSize;
    167    int32_t biWidth;
    168    int32_t biHeight;
    169    uint16_t biPlanes;
    170    uint16_t biBitCount;
    171    uint32_t biCompression;
    172    uint32_t biSizeImage;
    173    int32_t biXPelsPerMeter;
    174    int32_t biYPelsPerMeter;
    175    uint32_t biClrUsed;
    176    uint32_t biClrImportant;
    177 };
    178 
    179 struct bmp_rgb_quad {
    180    uint8_t rgbBlue;
    181    uint8_t rgbGreen;
    182    uint8_t rgbRed;
    183    uint8_t rgbAlpha;
    184 };
    185 
    186 void
    187 debug_dump_surface_bmp(struct pipe_context *pipe,
    188                        const char *filename,
    189                        struct pipe_surface *surface)
    190 {
    191    struct pipe_transfer *transfer;
    192    struct pipe_resource *texture = surface->texture;
    193    void *ptr;
    194 
    195    ptr = pipe_transfer_map(pipe, texture, surface->u.tex.level,
    196                            surface->u.tex.first_layer, PIPE_TRANSFER_READ,
    197                            0, 0, surface->width, surface->height, &transfer);
    198 
    199    debug_dump_transfer_bmp(pipe, filename, transfer, ptr);
    200 
    201    pipe->transfer_unmap(pipe, transfer);
    202 }
    203 
    204 void
    205 debug_dump_transfer_bmp(struct pipe_context *pipe,
    206                         const char *filename,
    207                         struct pipe_transfer *transfer, void *ptr)
    208 {
    209    float *rgba;
    210 
    211    if (!transfer)
    212       goto error1;
    213 
    214    rgba = MALLOC(transfer->box.width *
    215 		 transfer->box.height *
    216 		 transfer->box.depth *
    217 		 4*sizeof(float));
    218    if (!rgba)
    219       goto error1;
    220 
    221    pipe_get_tile_rgba(transfer, ptr, 0, 0,
    222                       transfer->box.width, transfer->box.height,
    223                       rgba);
    224 
    225    debug_dump_float_rgba_bmp(filename,
    226                              transfer->box.width, transfer->box.height,
    227                              rgba, transfer->box.width);
    228 
    229    FREE(rgba);
    230 error1:
    231    ;
    232 }
    233 
    234 void
    235 debug_dump_float_rgba_bmp(const char *filename,
    236                           unsigned width, unsigned height,
    237                           float *rgba, unsigned stride)
    238 {
    239    FILE *stream;
    240    struct bmp_file_header bmfh;
    241    struct bmp_info_header bmih;
    242    unsigned x, y;
    243 
    244    if (!rgba)
    245       goto error1;
    246 
    247    bmfh.bfType = 0x4d42;
    248    bmfh.bfSize = 14 + 40 + height*width*4;
    249    bmfh.bfReserved1 = 0;
    250    bmfh.bfReserved2 = 0;
    251    bmfh.bfOffBits = 14 + 40;
    252 
    253    bmih.biSize = 40;
    254    bmih.biWidth = width;
    255    bmih.biHeight = height;
    256    bmih.biPlanes = 1;
    257    bmih.biBitCount = 32;
    258    bmih.biCompression = 0;
    259    bmih.biSizeImage = height*width*4;
    260    bmih.biXPelsPerMeter = 0;
    261    bmih.biYPelsPerMeter = 0;
    262    bmih.biClrUsed = 0;
    263    bmih.biClrImportant = 0;
    264 
    265    stream = fopen(filename, "wb");
    266    if (!stream)
    267       goto error1;
    268 
    269    fwrite(&bmfh, 14, 1, stream);
    270    fwrite(&bmih, 40, 1, stream);
    271 
    272    y = height;
    273    while (y--) {
    274       float *ptr = rgba + (stride * y * 4);
    275       for (x = 0; x < width; ++x) {
    276          struct bmp_rgb_quad pixel;
    277          pixel.rgbRed   = float_to_ubyte(ptr[x*4 + 0]);
    278          pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
    279          pixel.rgbBlue  = float_to_ubyte(ptr[x*4 + 2]);
    280          pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]);
    281          fwrite(&pixel, 1, 4, stream);
    282       }
    283    }
    284 
    285    fclose(stream);
    286 error1:
    287    ;
    288 }
    289 
    290 void
    291 debug_dump_ubyte_rgba_bmp(const char *filename,
    292                           unsigned width, unsigned height,
    293                           const ubyte *rgba, unsigned stride)
    294 {
    295    FILE *stream;
    296    struct bmp_file_header bmfh;
    297    struct bmp_info_header bmih;
    298    unsigned x, y;
    299 
    300    assert(rgba);
    301    if (!rgba)
    302       goto error1;
    303 
    304    bmfh.bfType = 0x4d42;
    305    bmfh.bfSize = 14 + 40 + height*width*4;
    306    bmfh.bfReserved1 = 0;
    307    bmfh.bfReserved2 = 0;
    308    bmfh.bfOffBits = 14 + 40;
    309 
    310    bmih.biSize = 40;
    311    bmih.biWidth = width;
    312    bmih.biHeight = height;
    313    bmih.biPlanes = 1;
    314    bmih.biBitCount = 32;
    315    bmih.biCompression = 0;
    316    bmih.biSizeImage = height*width*4;
    317    bmih.biXPelsPerMeter = 0;
    318    bmih.biYPelsPerMeter = 0;
    319    bmih.biClrUsed = 0;
    320    bmih.biClrImportant = 0;
    321 
    322    stream = fopen(filename, "wb");
    323    assert(stream);
    324    if (!stream)
    325       goto error1;
    326 
    327    fwrite(&bmfh, 14, 1, stream);
    328    fwrite(&bmih, 40, 1, stream);
    329 
    330    y = height;
    331    while (y--) {
    332       const ubyte *ptr = rgba + (stride * y * 4);
    333       for (x = 0; x < width; ++x) {
    334          struct bmp_rgb_quad pixel;
    335          pixel.rgbRed   = ptr[x*4 + 0];
    336          pixel.rgbGreen = ptr[x*4 + 1];
    337          pixel.rgbBlue  = ptr[x*4 + 2];
    338          pixel.rgbAlpha = ptr[x*4 + 3];
    339          fwrite(&pixel, 1, 4, stream);
    340       }
    341    }
    342 
    343    fclose(stream);
    344 error1:
    345    ;
    346 }
    347 
    348 #endif
    349