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