1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 5848b8605Smrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the "Software"), 9848b8605Smrg * to deal in the Software without restriction, including without limitation 10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 12848b8605Smrg * Software is furnished to do so, subject to the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice shall be included 15848b8605Smrg * in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg */ 25848b8605Smrg 26b8e80941Smrg#include <stdio.h> 27b8e80941Smrg#include "errors.h" 28848b8605Smrg#include "mtypes.h" 29848b8605Smrg#include "attrib.h" 30848b8605Smrg#include "enums.h" 31848b8605Smrg#include "formats.h" 32848b8605Smrg#include "hash.h" 33848b8605Smrg#include "imports.h" 34b8e80941Smrg#include "macros.h" 35848b8605Smrg#include "debug.h" 36848b8605Smrg#include "get.h" 37848b8605Smrg#include "pixelstore.h" 38848b8605Smrg#include "readpix.h" 39848b8605Smrg#include "texobj.h" 40848b8605Smrg 41848b8605Smrg 42848b8605Smrgstatic const char * 43848b8605Smrgtex_target_name(GLenum tgt) 44848b8605Smrg{ 45848b8605Smrg static const struct { 46848b8605Smrg GLenum target; 47848b8605Smrg const char *name; 48848b8605Smrg } tex_targets[] = { 49848b8605Smrg { GL_TEXTURE_1D, "GL_TEXTURE_1D" }, 50848b8605Smrg { GL_TEXTURE_2D, "GL_TEXTURE_2D" }, 51848b8605Smrg { GL_TEXTURE_3D, "GL_TEXTURE_3D" }, 52848b8605Smrg { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" }, 53848b8605Smrg { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" }, 54848b8605Smrg { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" }, 55848b8605Smrg { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" }, 56848b8605Smrg { GL_TEXTURE_CUBE_MAP_ARRAY, "GL_TEXTURE_CUBE_MAP_ARRAY" }, 57848b8605Smrg { GL_TEXTURE_BUFFER, "GL_TEXTURE_BUFFER" }, 58848b8605Smrg { GL_TEXTURE_2D_MULTISAMPLE, "GL_TEXTURE_2D_MULTISAMPLE" }, 59848b8605Smrg { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "GL_TEXTURE_2D_MULTISAMPLE_ARRAY" }, 60848b8605Smrg { GL_TEXTURE_EXTERNAL_OES, "GL_TEXTURE_EXTERNAL_OES" } 61848b8605Smrg }; 62848b8605Smrg GLuint i; 63b8e80941Smrg STATIC_ASSERT(ARRAY_SIZE(tex_targets) == NUM_TEXTURE_TARGETS); 64b8e80941Smrg for (i = 0; i < ARRAY_SIZE(tex_targets); i++) { 65848b8605Smrg if (tex_targets[i].target == tgt) 66848b8605Smrg return tex_targets[i].name; 67848b8605Smrg } 68848b8605Smrg return "UNKNOWN TEX TARGET"; 69848b8605Smrg} 70848b8605Smrg 71848b8605Smrg 72848b8605Smrgvoid 73848b8605Smrg_mesa_print_state( const char *msg, GLuint state ) 74848b8605Smrg{ 75848b8605Smrg _mesa_debug(NULL, 76848b8605Smrg "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", 77848b8605Smrg msg, 78848b8605Smrg state, 79848b8605Smrg (state & _NEW_MODELVIEW) ? "ctx->ModelView, " : "", 80848b8605Smrg (state & _NEW_PROJECTION) ? "ctx->Projection, " : "", 81848b8605Smrg (state & _NEW_TEXTURE_MATRIX) ? "ctx->TextureMatrix, " : "", 82848b8605Smrg (state & _NEW_COLOR) ? "ctx->Color, " : "", 83848b8605Smrg (state & _NEW_DEPTH) ? "ctx->Depth, " : "", 84848b8605Smrg (state & _NEW_EVAL) ? "ctx->Eval/EvalMap, " : "", 85848b8605Smrg (state & _NEW_FOG) ? "ctx->Fog, " : "", 86848b8605Smrg (state & _NEW_HINT) ? "ctx->Hint, " : "", 87848b8605Smrg (state & _NEW_LIGHT) ? "ctx->Light, " : "", 88848b8605Smrg (state & _NEW_LINE) ? "ctx->Line, " : "", 89848b8605Smrg (state & _NEW_PIXEL) ? "ctx->Pixel, " : "", 90848b8605Smrg (state & _NEW_POINT) ? "ctx->Point, " : "", 91848b8605Smrg (state & _NEW_POLYGON) ? "ctx->Polygon, " : "", 92848b8605Smrg (state & _NEW_POLYGONSTIPPLE) ? "ctx->PolygonStipple, " : "", 93848b8605Smrg (state & _NEW_SCISSOR) ? "ctx->Scissor, " : "", 94848b8605Smrg (state & _NEW_STENCIL) ? "ctx->Stencil, " : "", 95b8e80941Smrg (state & _NEW_TEXTURE_OBJECT) ? "ctx->Texture(Object), " : "", 96848b8605Smrg (state & _NEW_TRANSFORM) ? "ctx->Transform, " : "", 97848b8605Smrg (state & _NEW_VIEWPORT) ? "ctx->Viewport, " : "", 98b8e80941Smrg (state & _NEW_TEXTURE_STATE) ? "ctx->Texture(State), " : "", 99848b8605Smrg (state & _NEW_RENDERMODE) ? "ctx->RenderMode, " : "", 100848b8605Smrg (state & _NEW_BUFFERS) ? "ctx->Visual, ctx->DrawBuffer,, " : ""); 101848b8605Smrg} 102848b8605Smrg 103848b8605Smrg 104848b8605Smrg 105848b8605Smrg/** 106848b8605Smrg * Print information about this Mesa version and build options. 107848b8605Smrg */ 108848b8605Smrgvoid _mesa_print_info( struct gl_context *ctx ) 109848b8605Smrg{ 110848b8605Smrg _mesa_debug(NULL, "Mesa GL_VERSION = %s\n", 111848b8605Smrg (char *) _mesa_GetString(GL_VERSION)); 112848b8605Smrg _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n", 113848b8605Smrg (char *) _mesa_GetString(GL_RENDERER)); 114848b8605Smrg _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n", 115848b8605Smrg (char *) _mesa_GetString(GL_VENDOR)); 116848b8605Smrg 117848b8605Smrg /* use ctx as GL_EXTENSIONS will not work on 3.0 or higher 118848b8605Smrg * core contexts. 119848b8605Smrg */ 120848b8605Smrg _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", ctx->Extensions.String); 121848b8605Smrg 122848b8605Smrg#if defined(USE_X86_ASM) 123848b8605Smrg _mesa_debug(NULL, "Mesa x86-optimized: YES\n"); 124848b8605Smrg#else 125848b8605Smrg _mesa_debug(NULL, "Mesa x86-optimized: NO\n"); 126848b8605Smrg#endif 127848b8605Smrg#if defined(USE_SPARC_ASM) 128848b8605Smrg _mesa_debug(NULL, "Mesa sparc-optimized: YES\n"); 129848b8605Smrg#else 130848b8605Smrg _mesa_debug(NULL, "Mesa sparc-optimized: NO\n"); 131848b8605Smrg#endif 132848b8605Smrg} 133848b8605Smrg 134848b8605Smrg 135848b8605Smrg/** 136848b8605Smrg * Set verbose logging flags. When these flags are set, GL API calls 137848b8605Smrg * in the various categories will be printed to stderr. 138848b8605Smrg * \param str a comma-separated list of keywords 139848b8605Smrg */ 140848b8605Smrgstatic void 141848b8605Smrgset_verbose_flags(const char *str) 142848b8605Smrg{ 143848b8605Smrg#ifdef DEBUG 144848b8605Smrg struct option { 145848b8605Smrg const char *name; 146848b8605Smrg GLbitfield flag; 147848b8605Smrg }; 148848b8605Smrg static const struct option opts[] = { 149848b8605Smrg { "varray", VERBOSE_VARRAY }, 150848b8605Smrg { "tex", VERBOSE_TEXTURE }, 151848b8605Smrg { "mat", VERBOSE_MATERIAL }, 152848b8605Smrg { "pipe", VERBOSE_PIPELINE }, 153848b8605Smrg { "driver", VERBOSE_DRIVER }, 154848b8605Smrg { "state", VERBOSE_STATE }, 155848b8605Smrg { "api", VERBOSE_API }, 156848b8605Smrg { "list", VERBOSE_DISPLAY_LIST }, 157848b8605Smrg { "lighting", VERBOSE_LIGHTING }, 158848b8605Smrg { "disassem", VERBOSE_DISASSEM }, 159848b8605Smrg { "draw", VERBOSE_DRAW }, 160848b8605Smrg { "swap", VERBOSE_SWAPBUFFERS } 161848b8605Smrg }; 162848b8605Smrg GLuint i; 163848b8605Smrg 164848b8605Smrg if (!str) 165848b8605Smrg return; 166848b8605Smrg 167848b8605Smrg MESA_VERBOSE = 0x0; 168b8e80941Smrg for (i = 0; i < ARRAY_SIZE(opts); i++) { 169848b8605Smrg if (strstr(str, opts[i].name) || strcmp(str, "all") == 0) 170848b8605Smrg MESA_VERBOSE |= opts[i].flag; 171848b8605Smrg } 172848b8605Smrg#endif 173848b8605Smrg} 174848b8605Smrg 175848b8605Smrg 176848b8605Smrg/** 177848b8605Smrg * Set debugging flags. When these flags are set, Mesa will do additional 178848b8605Smrg * debug checks or actions. 179848b8605Smrg * \param str a comma-separated list of keywords 180848b8605Smrg */ 181848b8605Smrgstatic void 182848b8605Smrgset_debug_flags(const char *str) 183848b8605Smrg{ 184848b8605Smrg#ifdef DEBUG 185848b8605Smrg struct option { 186848b8605Smrg const char *name; 187848b8605Smrg GLbitfield flag; 188848b8605Smrg }; 189848b8605Smrg static const struct option opts[] = { 190848b8605Smrg { "silent", DEBUG_SILENT }, /* turn off debug messages */ 191848b8605Smrg { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */ 192848b8605Smrg { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE }, 193b8e80941Smrg { "incomplete_fbo", DEBUG_INCOMPLETE_FBO }, 194b8e80941Smrg { "context", DEBUG_CONTEXT } /* force set GL_CONTEXT_FLAG_DEBUG_BIT flag */ 195848b8605Smrg }; 196848b8605Smrg GLuint i; 197848b8605Smrg 198848b8605Smrg if (!str) 199848b8605Smrg return; 200848b8605Smrg 201848b8605Smrg MESA_DEBUG_FLAGS = 0x0; 202b8e80941Smrg for (i = 0; i < ARRAY_SIZE(opts); i++) { 203848b8605Smrg if (strstr(str, opts[i].name)) 204848b8605Smrg MESA_DEBUG_FLAGS |= opts[i].flag; 205848b8605Smrg } 206848b8605Smrg#endif 207848b8605Smrg} 208848b8605Smrg 209848b8605Smrg 210848b8605Smrg/** 211848b8605Smrg * Initialize debugging variables from env vars. 212848b8605Smrg */ 213848b8605Smrgvoid 214848b8605Smrg_mesa_init_debug( struct gl_context *ctx ) 215848b8605Smrg{ 216b8e80941Smrg set_debug_flags(getenv("MESA_DEBUG")); 217b8e80941Smrg set_verbose_flags(getenv("MESA_VERBOSE")); 218848b8605Smrg} 219848b8605Smrg 220848b8605Smrg 221848b8605Smrg/* 222848b8605Smrg * Write ppm file 223848b8605Smrg */ 224848b8605Smrgstatic void 225848b8605Smrgwrite_ppm(const char *filename, const GLubyte *buffer, int width, int height, 226848b8605Smrg int comps, int rcomp, int gcomp, int bcomp, GLboolean invert) 227848b8605Smrg{ 228848b8605Smrg FILE *f = fopen( filename, "w" ); 229848b8605Smrg if (f) { 230848b8605Smrg int x, y; 231848b8605Smrg const GLubyte *ptr = buffer; 232848b8605Smrg fprintf(f,"P6\n"); 233848b8605Smrg fprintf(f,"# ppm-file created by osdemo.c\n"); 234848b8605Smrg fprintf(f,"%i %i\n", width,height); 235848b8605Smrg fprintf(f,"255\n"); 236848b8605Smrg fclose(f); 237848b8605Smrg f = fopen( filename, "ab" ); /* reopen in binary append mode */ 238b8e80941Smrg if (!f) { 239b8e80941Smrg fprintf(stderr, "Error while reopening %s in write_ppm()\n", 240b8e80941Smrg filename); 241b8e80941Smrg return; 242b8e80941Smrg } 243848b8605Smrg for (y=0; y < height; y++) { 244848b8605Smrg for (x = 0; x < width; x++) { 245848b8605Smrg int yy = invert ? (height - 1 - y) : y; 246848b8605Smrg int i = (yy * width + x) * comps; 247848b8605Smrg fputc(ptr[i+rcomp], f); /* write red */ 248848b8605Smrg fputc(ptr[i+gcomp], f); /* write green */ 249848b8605Smrg fputc(ptr[i+bcomp], f); /* write blue */ 250848b8605Smrg } 251848b8605Smrg } 252848b8605Smrg fclose(f); 253848b8605Smrg } 254848b8605Smrg else { 255848b8605Smrg fprintf(stderr, "Unable to create %s in write_ppm()\n", filename); 256848b8605Smrg } 257848b8605Smrg} 258848b8605Smrg 259848b8605Smrg 260848b8605Smrg/** 261848b8605Smrg * Write a texture image to a ppm file. 262848b8605Smrg * \param face cube face in [0,5] 263848b8605Smrg * \param level mipmap level 264848b8605Smrg */ 265848b8605Smrgstatic void 266848b8605Smrgwrite_texture_image(struct gl_texture_object *texObj, 267848b8605Smrg GLuint face, GLuint level) 268848b8605Smrg{ 269848b8605Smrg struct gl_texture_image *img = texObj->Image[face][level]; 270848b8605Smrg if (img) { 271848b8605Smrg GET_CURRENT_CONTEXT(ctx); 272848b8605Smrg struct gl_pixelstore_attrib store; 273848b8605Smrg GLubyte *buffer; 274848b8605Smrg char s[100]; 275848b8605Smrg 276848b8605Smrg buffer = malloc(img->Width * img->Height 277848b8605Smrg * img->Depth * 4); 278848b8605Smrg 279848b8605Smrg store = ctx->Pack; /* save */ 280848b8605Smrg ctx->Pack = ctx->DefaultPacking; 281848b8605Smrg 282b8e80941Smrg ctx->Driver.GetTexSubImage(ctx, 283b8e80941Smrg 0, 0, 0, img->Width, img->Height, img->Depth, 284b8e80941Smrg GL_RGBA, GL_UNSIGNED_BYTE, buffer, img); 285848b8605Smrg 286848b8605Smrg /* make filename */ 287848b8605Smrg _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face); 288848b8605Smrg 289848b8605Smrg printf(" Writing image level %u to %s\n", level, s); 290848b8605Smrg write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE); 291848b8605Smrg 292848b8605Smrg ctx->Pack = store; /* restore */ 293848b8605Smrg 294848b8605Smrg free(buffer); 295848b8605Smrg } 296848b8605Smrg} 297848b8605Smrg 298848b8605Smrg 299848b8605Smrg/** 300848b8605Smrg * Write renderbuffer image to a ppm file. 301848b8605Smrg */ 302848b8605Smrgvoid 303848b8605Smrg_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb) 304848b8605Smrg{ 305848b8605Smrg GET_CURRENT_CONTEXT(ctx); 306848b8605Smrg GLubyte *buffer; 307848b8605Smrg char s[100]; 308848b8605Smrg GLenum format, type; 309848b8605Smrg 310848b8605Smrg if (rb->_BaseFormat == GL_RGB || 311848b8605Smrg rb->_BaseFormat == GL_RGBA) { 312848b8605Smrg format = GL_RGBA; 313848b8605Smrg type = GL_UNSIGNED_BYTE; 314848b8605Smrg } 315848b8605Smrg else if (rb->_BaseFormat == GL_DEPTH_STENCIL) { 316848b8605Smrg format = GL_DEPTH_STENCIL; 317848b8605Smrg type = GL_UNSIGNED_INT_24_8; 318848b8605Smrg } 319848b8605Smrg else { 320848b8605Smrg _mesa_debug(NULL, 321848b8605Smrg "Unsupported BaseFormat 0x%x in " 322848b8605Smrg "_mesa_write_renderbuffer_image()\n", 323848b8605Smrg rb->_BaseFormat); 324848b8605Smrg return; 325848b8605Smrg } 326848b8605Smrg 327848b8605Smrg buffer = malloc(rb->Width * rb->Height * 4); 328848b8605Smrg 329848b8605Smrg ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height, 330848b8605Smrg format, type, &ctx->DefaultPacking, buffer); 331848b8605Smrg 332848b8605Smrg /* make filename */ 333848b8605Smrg _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name); 334848b8605Smrg _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name); 335848b8605Smrg 336848b8605Smrg printf(" Writing renderbuffer image to %s\n", s); 337848b8605Smrg 338848b8605Smrg _mesa_debug(NULL, " Writing renderbuffer image to %s\n", s); 339848b8605Smrg 340848b8605Smrg write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE); 341848b8605Smrg 342848b8605Smrg free(buffer); 343848b8605Smrg} 344848b8605Smrg 345848b8605Smrg 346848b8605Smrg/** How many texture images (mipmap levels, faces) to write to files */ 347848b8605Smrg#define WRITE_NONE 0 348848b8605Smrg#define WRITE_ONE 1 349848b8605Smrg#define WRITE_ALL 2 350848b8605Smrg 351848b8605Smrgstatic GLuint WriteImages; 352848b8605Smrg 353848b8605Smrg 354848b8605Smrgstatic void 355848b8605Smrgdump_texture(struct gl_texture_object *texObj, GLuint writeImages) 356848b8605Smrg{ 357848b8605Smrg const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1; 358848b8605Smrg GLboolean written = GL_FALSE; 359848b8605Smrg GLuint i, j; 360848b8605Smrg 361848b8605Smrg printf("Texture %u\n", texObj->Name); 362848b8605Smrg printf(" Target %s\n", tex_target_name(texObj->Target)); 363848b8605Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 364848b8605Smrg for (j = 0; j < numFaces; j++) { 365848b8605Smrg struct gl_texture_image *texImg = texObj->Image[j][i]; 366848b8605Smrg if (texImg) { 367848b8605Smrg printf(" Face %u level %u: %d x %d x %d, format %s\n", 368848b8605Smrg j, i, 369848b8605Smrg texImg->Width, texImg->Height, texImg->Depth, 370848b8605Smrg _mesa_get_format_name(texImg->TexFormat)); 371848b8605Smrg if (writeImages == WRITE_ALL || 372848b8605Smrg (writeImages == WRITE_ONE && !written)) { 373848b8605Smrg write_texture_image(texObj, j, i); 374848b8605Smrg written = GL_TRUE; 375848b8605Smrg } 376848b8605Smrg } 377848b8605Smrg } 378848b8605Smrg } 379848b8605Smrg} 380848b8605Smrg 381848b8605Smrg 382848b8605Smrg/** 383848b8605Smrg * Dump a single texture. 384848b8605Smrg */ 385848b8605Smrgvoid 386848b8605Smrg_mesa_dump_texture(GLuint texture, GLuint writeImages) 387848b8605Smrg{ 388848b8605Smrg GET_CURRENT_CONTEXT(ctx); 389848b8605Smrg struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture); 390848b8605Smrg if (texObj) { 391848b8605Smrg dump_texture(texObj, writeImages); 392848b8605Smrg } 393848b8605Smrg} 394848b8605Smrg 395848b8605Smrg 396848b8605Smrgstatic void 397848b8605Smrgdump_texture_cb(GLuint id, void *data, void *userData) 398848b8605Smrg{ 399848b8605Smrg struct gl_texture_object *texObj = (struct gl_texture_object *) data; 400848b8605Smrg (void) userData; 401848b8605Smrg dump_texture(texObj, WriteImages); 402848b8605Smrg} 403848b8605Smrg 404848b8605Smrg 405848b8605Smrg/** 406848b8605Smrg * Print basic info about all texture objext to stdout. 407848b8605Smrg * If dumpImages is true, write PPM of level[0] image to a file. 408848b8605Smrg */ 409848b8605Smrgvoid 410848b8605Smrg_mesa_dump_textures(GLuint writeImages) 411848b8605Smrg{ 412848b8605Smrg GET_CURRENT_CONTEXT(ctx); 413848b8605Smrg WriteImages = writeImages; 414848b8605Smrg _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx); 415848b8605Smrg} 416848b8605Smrg 417848b8605Smrg 418848b8605Smrgstatic void 419848b8605Smrgdump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage) 420848b8605Smrg{ 421848b8605Smrg printf("Renderbuffer %u: %u x %u IntFormat = %s\n", 422848b8605Smrg rb->Name, rb->Width, rb->Height, 423b8e80941Smrg _mesa_enum_to_string(rb->InternalFormat)); 424848b8605Smrg if (writeImage) { 425848b8605Smrg _mesa_write_renderbuffer_image(rb); 426848b8605Smrg } 427848b8605Smrg} 428848b8605Smrg 429848b8605Smrg 430848b8605Smrgstatic void 431848b8605Smrgdump_renderbuffer_cb(GLuint id, void *data, void *userData) 432848b8605Smrg{ 433848b8605Smrg const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data; 434848b8605Smrg (void) userData; 435848b8605Smrg dump_renderbuffer(rb, WriteImages); 436848b8605Smrg} 437848b8605Smrg 438848b8605Smrg 439848b8605Smrg/** 440848b8605Smrg * Print basic info about all renderbuffers to stdout. 441848b8605Smrg * If dumpImages is true, write PPM of level[0] image to a file. 442848b8605Smrg */ 443848b8605Smrgvoid 444848b8605Smrg_mesa_dump_renderbuffers(GLboolean writeImages) 445848b8605Smrg{ 446848b8605Smrg GET_CURRENT_CONTEXT(ctx); 447848b8605Smrg WriteImages = writeImages; 448848b8605Smrg _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx); 449848b8605Smrg} 450848b8605Smrg 451848b8605Smrg 452848b8605Smrg 453848b8605Smrgvoid 454848b8605Smrg_mesa_dump_color_buffer(const char *filename) 455848b8605Smrg{ 456848b8605Smrg GET_CURRENT_CONTEXT(ctx); 457848b8605Smrg const GLuint w = ctx->DrawBuffer->Width; 458848b8605Smrg const GLuint h = ctx->DrawBuffer->Height; 459848b8605Smrg GLubyte *buf; 460848b8605Smrg 461848b8605Smrg buf = malloc(w * h * 4); 462848b8605Smrg 463848b8605Smrg _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 464848b8605Smrg _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); 465848b8605Smrg _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); 466848b8605Smrg 467848b8605Smrg _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf); 468848b8605Smrg 469848b8605Smrg printf("ReadBuffer %p 0x%x DrawBuffer %p 0x%x\n", 470848b8605Smrg (void *) ctx->ReadBuffer->_ColorReadBuffer, 471848b8605Smrg ctx->ReadBuffer->ColorReadBuffer, 472848b8605Smrg (void *) ctx->DrawBuffer->_ColorDrawBuffers[0], 473848b8605Smrg ctx->DrawBuffer->ColorDrawBuffer[0]); 474848b8605Smrg printf("Writing %d x %d color buffer to %s\n", w, h, filename); 475848b8605Smrg write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE); 476848b8605Smrg 477848b8605Smrg _mesa_PopClientAttrib(); 478848b8605Smrg 479848b8605Smrg free(buf); 480848b8605Smrg} 481848b8605Smrg 482848b8605Smrg 483848b8605Smrgvoid 484848b8605Smrg_mesa_dump_depth_buffer(const char *filename) 485848b8605Smrg{ 486848b8605Smrg GET_CURRENT_CONTEXT(ctx); 487848b8605Smrg const GLuint w = ctx->DrawBuffer->Width; 488848b8605Smrg const GLuint h = ctx->DrawBuffer->Height; 489848b8605Smrg GLuint *buf; 490848b8605Smrg GLubyte *buf2; 491848b8605Smrg GLuint i; 492848b8605Smrg 493848b8605Smrg buf = malloc(w * h * 4); /* 4 bpp */ 494848b8605Smrg buf2 = malloc(w * h * 3); /* 3 bpp */ 495848b8605Smrg 496848b8605Smrg _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 497848b8605Smrg _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); 498848b8605Smrg _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); 499848b8605Smrg 500848b8605Smrg _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf); 501848b8605Smrg 502848b8605Smrg /* spread 24 bits of Z across R, G, B */ 503848b8605Smrg for (i = 0; i < w * h; i++) { 504848b8605Smrg buf2[i*3+0] = (buf[i] >> 24) & 0xff; 505848b8605Smrg buf2[i*3+1] = (buf[i] >> 16) & 0xff; 506848b8605Smrg buf2[i*3+2] = (buf[i] >> 8) & 0xff; 507848b8605Smrg } 508848b8605Smrg 509848b8605Smrg printf("Writing %d x %d depth buffer to %s\n", w, h, filename); 510848b8605Smrg write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE); 511848b8605Smrg 512848b8605Smrg _mesa_PopClientAttrib(); 513848b8605Smrg 514848b8605Smrg free(buf); 515848b8605Smrg free(buf2); 516848b8605Smrg} 517848b8605Smrg 518848b8605Smrg 519848b8605Smrgvoid 520848b8605Smrg_mesa_dump_stencil_buffer(const char *filename) 521848b8605Smrg{ 522848b8605Smrg GET_CURRENT_CONTEXT(ctx); 523848b8605Smrg const GLuint w = ctx->DrawBuffer->Width; 524848b8605Smrg const GLuint h = ctx->DrawBuffer->Height; 525848b8605Smrg GLubyte *buf; 526848b8605Smrg GLubyte *buf2; 527848b8605Smrg GLuint i; 528848b8605Smrg 529848b8605Smrg buf = malloc(w * h); /* 1 bpp */ 530848b8605Smrg buf2 = malloc(w * h * 3); /* 3 bpp */ 531848b8605Smrg 532848b8605Smrg _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 533848b8605Smrg _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); 534848b8605Smrg _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); 535848b8605Smrg 536848b8605Smrg _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf); 537848b8605Smrg 538848b8605Smrg for (i = 0; i < w * h; i++) { 539848b8605Smrg buf2[i*3+0] = buf[i]; 540848b8605Smrg buf2[i*3+1] = (buf[i] & 127) * 2; 541848b8605Smrg buf2[i*3+2] = (buf[i] - 128) * 2; 542848b8605Smrg } 543848b8605Smrg 544848b8605Smrg printf("Writing %d x %d stencil buffer to %s\n", w, h, filename); 545848b8605Smrg write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE); 546848b8605Smrg 547848b8605Smrg _mesa_PopClientAttrib(); 548848b8605Smrg 549848b8605Smrg free(buf); 550848b8605Smrg free(buf2); 551848b8605Smrg} 552848b8605Smrg 553848b8605Smrg 554848b8605Smrgvoid 555848b8605Smrg_mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h, 556848b8605Smrg GLenum format, GLenum type) 557848b8605Smrg{ 558848b8605Smrg GLboolean invert = GL_TRUE; 559848b8605Smrg 560848b8605Smrg if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) { 561848b8605Smrg write_ppm(filename, image, w, h, 4, 0, 1, 2, invert); 562848b8605Smrg } 563848b8605Smrg else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) { 564848b8605Smrg write_ppm(filename, image, w, h, 4, 2, 1, 0, invert); 565848b8605Smrg } 566848b8605Smrg else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) { 567848b8605Smrg write_ppm(filename, image, w, h, 2, 1, 0, 0, invert); 568848b8605Smrg } 569848b8605Smrg else if (format == GL_RED && type == GL_UNSIGNED_BYTE) { 570848b8605Smrg write_ppm(filename, image, w, h, 1, 0, 0, 0, invert); 571848b8605Smrg } 572848b8605Smrg else if (format == GL_RGBA && type == GL_FLOAT) { 573848b8605Smrg /* convert floats to ubyte */ 574848b8605Smrg GLubyte *buf = malloc(w * h * 4 * sizeof(GLubyte)); 575848b8605Smrg const GLfloat *f = (const GLfloat *) image; 576848b8605Smrg GLuint i; 577848b8605Smrg for (i = 0; i < w * h * 4; i++) { 578848b8605Smrg UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]); 579848b8605Smrg } 580848b8605Smrg write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert); 581848b8605Smrg free(buf); 582848b8605Smrg } 583848b8605Smrg else if (format == GL_RED && type == GL_FLOAT) { 584848b8605Smrg /* convert floats to ubyte */ 585848b8605Smrg GLubyte *buf = malloc(w * h * sizeof(GLubyte)); 586848b8605Smrg const GLfloat *f = (const GLfloat *) image; 587848b8605Smrg GLuint i; 588848b8605Smrg for (i = 0; i < w * h; i++) { 589848b8605Smrg UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]); 590848b8605Smrg } 591848b8605Smrg write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert); 592848b8605Smrg free(buf); 593848b8605Smrg } 594848b8605Smrg else { 595848b8605Smrg _mesa_problem(NULL, 596848b8605Smrg "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()", 597848b8605Smrg format, type); 598848b8605Smrg } 599848b8605Smrg} 600848b8605Smrg 601848b8605Smrg 602848b8605Smrg/** 603848b8605Smrg * Quick and dirty function to "print" a texture to stdout. 604848b8605Smrg */ 605848b8605Smrgvoid 606848b8605Smrg_mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img) 607848b8605Smrg{ 608848b8605Smrg const GLint slice = 0; 609848b8605Smrg GLint srcRowStride; 610848b8605Smrg GLuint i, j, c; 611848b8605Smrg GLubyte *data; 612848b8605Smrg 613848b8605Smrg ctx->Driver.MapTextureImage(ctx, img, slice, 614848b8605Smrg 0, 0, img->Width, img->Height, GL_MAP_READ_BIT, 615848b8605Smrg &data, &srcRowStride); 616848b8605Smrg 617848b8605Smrg if (!data) { 618848b8605Smrg printf("No texture data\n"); 619848b8605Smrg } 620848b8605Smrg else { 621848b8605Smrg /* XXX add more formats or make into a new format utility function */ 622848b8605Smrg switch (img->TexFormat) { 623848b8605Smrg case MESA_FORMAT_A_UNORM8: 624848b8605Smrg case MESA_FORMAT_L_UNORM8: 625848b8605Smrg case MESA_FORMAT_I_UNORM8: 626848b8605Smrg c = 1; 627848b8605Smrg break; 628848b8605Smrg case MESA_FORMAT_L8A8_UNORM: 629848b8605Smrg case MESA_FORMAT_A8L8_UNORM: 630848b8605Smrg c = 2; 631848b8605Smrg break; 632848b8605Smrg case MESA_FORMAT_BGR_UNORM8: 633848b8605Smrg case MESA_FORMAT_RGB_UNORM8: 634848b8605Smrg c = 3; 635848b8605Smrg break; 636848b8605Smrg case MESA_FORMAT_A8B8G8R8_UNORM: 637848b8605Smrg case MESA_FORMAT_B8G8R8A8_UNORM: 638848b8605Smrg c = 4; 639848b8605Smrg break; 640848b8605Smrg default: 641848b8605Smrg _mesa_problem(NULL, "error in PrintTexture\n"); 642848b8605Smrg return; 643848b8605Smrg } 644848b8605Smrg 645848b8605Smrg for (i = 0; i < img->Height; i++) { 646848b8605Smrg for (j = 0; j < img->Width; j++) { 647848b8605Smrg if (c==1) 648848b8605Smrg printf("%02x ", data[0]); 649848b8605Smrg else if (c==2) 650848b8605Smrg printf("%02x%02x ", data[0], data[1]); 651848b8605Smrg else if (c==3) 652848b8605Smrg printf("%02x%02x%02x ", data[0], data[1], data[2]); 653848b8605Smrg else if (c==4) 654848b8605Smrg printf("%02x%02x%02x%02x ", data[0], data[1], data[2], data[3]); 655848b8605Smrg data += (srcRowStride - img->Width) * c; 656848b8605Smrg } 657848b8605Smrg /* XXX use img->ImageStride here */ 658848b8605Smrg printf("\n"); 659848b8605Smrg 660848b8605Smrg } 661848b8605Smrg } 662848b8605Smrg 663848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, img, slice); 664848b8605Smrg} 665