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