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 */ 48void 49debug_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... */ 96void 97debug_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 135void 136debug_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) 156struct 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 165struct 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 179struct bmp_rgb_quad { 180 uint8_t rgbBlue; 181 uint8_t rgbGreen; 182 uint8_t rgbRed; 183 uint8_t rgbAlpha; 184}; 185 186void 187debug_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 204void 205debug_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); 231error1: 232 ; 233} 234 235void 236debug_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); 287error1: 288 ; 289} 290 291void 292debug_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); 345error1: 346 ; 347} 348 349#endif 350