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/format/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
debug_dump_image(const char * prefix,enum pipe_format format,UNUSED unsigned cpp,unsigned width,unsigned height,unsigned stride,const void * data)49 debug_dump_image(const char *prefix,
50                  enum pipe_format format, UNUSED 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    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
debug_dump_surface(struct pipe_context * pipe,const char * prefix,struct pipe_surface * surface)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_texture_map(pipe, texture, surface->u.tex.level,
117                            surface->u.tex.first_layer,
118                            PIPE_MAP_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->texture_unmap(pipe, transfer);
132 }
133 
134 
135 void
debug_dump_texture(struct pipe_context * pipe,const char * prefix,struct pipe_resource * texture)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
debug_dump_surface_bmp(struct pipe_context * pipe,const char * filename,struct pipe_surface * surface)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_texture_map(pipe, texture, surface->u.tex.level,
196                           surface->u.tex.first_layer, PIPE_MAP_READ,
197                           0, 0, surface->width, surface->height, &transfer);
198 
199    debug_dump_transfer_bmp(pipe, filename, transfer, ptr);
200 
201    pipe->texture_unmap(pipe, transfer);
202 }
203 
204 void
debug_dump_transfer_bmp(UNUSED struct pipe_context * pipe,const char * filename,struct pipe_transfer * transfer,void * ptr)205 debug_dump_transfer_bmp(UNUSED 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                       transfer->resource->format,
224                       rgba);
225 
226    debug_dump_float_rgba_bmp(filename,
227                              transfer->box.width, transfer->box.height,
228                              rgba, transfer->box.width);
229 
230    FREE(rgba);
231 error1:
232    ;
233 }
234 
235 void
debug_dump_float_rgba_bmp(const char * filename,unsigned width,unsigned height,float * rgba,unsigned stride)236 debug_dump_float_rgba_bmp(const char *filename,
237                           unsigned width, unsigned height,
238                           float *rgba, unsigned stride)
239 {
240    FILE *stream;
241    struct bmp_file_header bmfh;
242    struct bmp_info_header bmih;
243    unsigned x, y;
244 
245    if (!rgba)
246       goto error1;
247 
248    bmfh.bfType = 0x4d42;
249    bmfh.bfSize = 14 + 40 + height*width*4;
250    bmfh.bfReserved1 = 0;
251    bmfh.bfReserved2 = 0;
252    bmfh.bfOffBits = 14 + 40;
253 
254    bmih.biSize = 40;
255    bmih.biWidth = width;
256    bmih.biHeight = height;
257    bmih.biPlanes = 1;
258    bmih.biBitCount = 32;
259    bmih.biCompression = 0;
260    bmih.biSizeImage = height*width*4;
261    bmih.biXPelsPerMeter = 0;
262    bmih.biYPelsPerMeter = 0;
263    bmih.biClrUsed = 0;
264    bmih.biClrImportant = 0;
265 
266    stream = fopen(filename, "wb");
267    if (!stream)
268       goto error1;
269 
270    fwrite(&bmfh, 14, 1, stream);
271    fwrite(&bmih, 40, 1, stream);
272 
273    y = height;
274    while (y--) {
275       float *ptr = rgba + (stride * y * 4);
276       for (x = 0; x < width; ++x) {
277          struct bmp_rgb_quad pixel;
278          pixel.rgbRed   = float_to_ubyte(ptr[x*4 + 0]);
279          pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
280          pixel.rgbBlue  = float_to_ubyte(ptr[x*4 + 2]);
281          pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]);
282          fwrite(&pixel, 1, 4, stream);
283       }
284    }
285 
286    fclose(stream);
287 error1:
288    ;
289 }
290 
291 void
debug_dump_ubyte_rgba_bmp(const char * filename,unsigned width,unsigned height,const ubyte * rgba,unsigned stride)292 debug_dump_ubyte_rgba_bmp(const char *filename,
293                           unsigned width, unsigned height,
294                           const ubyte *rgba, unsigned stride)
295 {
296    FILE *stream;
297    struct bmp_file_header bmfh;
298    struct bmp_info_header bmih;
299    unsigned x, y;
300 
301    assert(rgba);
302    if (!rgba)
303       goto error1;
304 
305    bmfh.bfType = 0x4d42;
306    bmfh.bfSize = 14 + 40 + height*width*4;
307    bmfh.bfReserved1 = 0;
308    bmfh.bfReserved2 = 0;
309    bmfh.bfOffBits = 14 + 40;
310 
311    bmih.biSize = 40;
312    bmih.biWidth = width;
313    bmih.biHeight = height;
314    bmih.biPlanes = 1;
315    bmih.biBitCount = 32;
316    bmih.biCompression = 0;
317    bmih.biSizeImage = height*width*4;
318    bmih.biXPelsPerMeter = 0;
319    bmih.biYPelsPerMeter = 0;
320    bmih.biClrUsed = 0;
321    bmih.biClrImportant = 0;
322 
323    stream = fopen(filename, "wb");
324    assert(stream);
325    if (!stream)
326       goto error1;
327 
328    fwrite(&bmfh, 14, 1, stream);
329    fwrite(&bmih, 40, 1, stream);
330 
331    y = height;
332    while (y--) {
333       const ubyte *ptr = rgba + (stride * y * 4);
334       for (x = 0; x < width; ++x) {
335          struct bmp_rgb_quad pixel;
336          pixel.rgbRed   = ptr[x*4 + 0];
337          pixel.rgbGreen = ptr[x*4 + 1];
338          pixel.rgbBlue  = ptr[x*4 + 2];
339          pixel.rgbAlpha = ptr[x*4 + 3];
340          fwrite(&pixel, 1, 4, stream);
341       }
342    }
343 
344    fclose(stream);
345 error1:
346    ;
347 }
348 
349 #endif
350