4e7984886d0d17b6b644664e3156df4fa84e87d8
[mesa.git] / src / gallium / auxiliary / util / u_debug_image.c
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, 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
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(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 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