debug.c revision 93bcf7825d023d3d7108bc47a7a0929338bba6b9
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26#include "mtypes.h" 27#include "attrib.h" 28#include "colormac.h" 29#include "enums.h" 30#include "formats.h" 31#include "hash.h" 32#include "imports.h" 33#include "debug.h" 34#include "get.h" 35#include "pixelstore.h" 36#include "readpix.h" 37#include "texobj.h" 38 39 40static const char * 41tex_target_name(GLenum tgt) 42{ 43 static const struct { 44 GLenum target; 45 const char *name; 46 } tex_targets[] = { 47 { GL_TEXTURE_1D, "GL_TEXTURE_1D" }, 48 { GL_TEXTURE_2D, "GL_TEXTURE_2D" }, 49 { GL_TEXTURE_3D, "GL_TEXTURE_3D" }, 50 { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" }, 51 { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" }, 52 { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" }, 53 { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" }, 54 { GL_TEXTURE_EXTERNAL_OES, "GL_TEXTURE_EXTERNAL_OES" } 55 }; 56 GLuint i; 57 for (i = 0; i < Elements(tex_targets); i++) { 58 if (tex_targets[i].target == tgt) 59 return tex_targets[i].name; 60 } 61 return "UNKNOWN TEX TARGET"; 62} 63 64 65void 66_mesa_print_state( const char *msg, GLuint state ) 67{ 68 _mesa_debug(NULL, 69 "%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%s\n", 70 msg, 71 state, 72 (state & _NEW_MODELVIEW) ? "ctx->ModelView, " : "", 73 (state & _NEW_PROJECTION) ? "ctx->Projection, " : "", 74 (state & _NEW_TEXTURE_MATRIX) ? "ctx->TextureMatrix, " : "", 75 (state & _NEW_COLOR) ? "ctx->Color, " : "", 76 (state & _NEW_DEPTH) ? "ctx->Depth, " : "", 77 (state & _NEW_EVAL) ? "ctx->Eval/EvalMap, " : "", 78 (state & _NEW_FOG) ? "ctx->Fog, " : "", 79 (state & _NEW_HINT) ? "ctx->Hint, " : "", 80 (state & _NEW_LIGHT) ? "ctx->Light, " : "", 81 (state & _NEW_LINE) ? "ctx->Line, " : "", 82 (state & _NEW_PIXEL) ? "ctx->Pixel, " : "", 83 (state & _NEW_POINT) ? "ctx->Point, " : "", 84 (state & _NEW_POLYGON) ? "ctx->Polygon, " : "", 85 (state & _NEW_POLYGONSTIPPLE) ? "ctx->PolygonStipple, " : "", 86 (state & _NEW_SCISSOR) ? "ctx->Scissor, " : "", 87 (state & _NEW_STENCIL) ? "ctx->Stencil, " : "", 88 (state & _NEW_TEXTURE) ? "ctx->Texture, " : "", 89 (state & _NEW_TRANSFORM) ? "ctx->Transform, " : "", 90 (state & _NEW_VIEWPORT) ? "ctx->Viewport, " : "", 91 (state & _NEW_PACKUNPACK) ? "ctx->Pack/Unpack, " : "", 92 (state & _NEW_ARRAY) ? "ctx->Array, " : "", 93 (state & _NEW_RENDERMODE) ? "ctx->RenderMode, " : "", 94 (state & _NEW_BUFFERS) ? "ctx->Visual, ctx->DrawBuffer,, " : ""); 95} 96 97 98 99void 100_mesa_print_tri_caps( const char *name, GLuint flags ) 101{ 102 _mesa_debug(NULL, 103 "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s\n", 104 name, 105 flags, 106 (flags & DD_SEPARATE_SPECULAR) ? "separate-specular, " : "", 107 (flags & DD_TRI_LIGHT_TWOSIDE) ? "tri-light-twoside, " : "", 108 (flags & DD_TRI_UNFILLED) ? "tri-unfilled, " : "", 109 (flags & DD_TRI_STIPPLE) ? "tri-stipple, " : "", 110 (flags & DD_TRI_OFFSET) ? "tri-offset, " : "", 111 (flags & DD_TRI_SMOOTH) ? "tri-smooth, " : "", 112 (flags & DD_LINE_SMOOTH) ? "line-smooth, " : "", 113 (flags & DD_LINE_STIPPLE) ? "line-stipple, " : "", 114 (flags & DD_POINT_SMOOTH) ? "point-smooth, " : "", 115 (flags & DD_POINT_ATTEN) ? "point-atten, " : "" 116 ); 117} 118 119 120/** 121 * Print information about this Mesa version and build options. 122 */ 123void _mesa_print_info( void ) 124{ 125 _mesa_debug(NULL, "Mesa GL_VERSION = %s\n", 126 (char *) _mesa_GetString(GL_VERSION)); 127 _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n", 128 (char *) _mesa_GetString(GL_RENDERER)); 129 _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n", 130 (char *) _mesa_GetString(GL_VENDOR)); 131 _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", 132 (char *) _mesa_GetString(GL_EXTENSIONS)); 133#if defined(THREADS) 134 _mesa_debug(NULL, "Mesa thread-safe: YES\n"); 135#else 136 _mesa_debug(NULL, "Mesa thread-safe: NO\n"); 137#endif 138#if defined(USE_X86_ASM) 139 _mesa_debug(NULL, "Mesa x86-optimized: YES\n"); 140#else 141 _mesa_debug(NULL, "Mesa x86-optimized: NO\n"); 142#endif 143#if defined(USE_SPARC_ASM) 144 _mesa_debug(NULL, "Mesa sparc-optimized: YES\n"); 145#else 146 _mesa_debug(NULL, "Mesa sparc-optimized: NO\n"); 147#endif 148} 149 150 151/** 152 * Set verbose logging flags. When these flags are set, GL API calls 153 * in the various categories will be printed to stderr. 154 * \param str a comma-separated list of keywords 155 */ 156static void 157set_verbose_flags(const char *str) 158{ 159#ifdef DEBUG 160 struct option { 161 const char *name; 162 GLbitfield flag; 163 }; 164 static const struct option opts[] = { 165 { "varray", VERBOSE_VARRAY }, 166 { "tex", VERBOSE_TEXTURE }, 167 { "mat", VERBOSE_MATERIAL }, 168 { "pipe", VERBOSE_PIPELINE }, 169 { "driver", VERBOSE_DRIVER }, 170 { "state", VERBOSE_STATE }, 171 { "api", VERBOSE_API }, 172 { "list", VERBOSE_DISPLAY_LIST }, 173 { "lighting", VERBOSE_LIGHTING }, 174 { "disassem", VERBOSE_DISASSEM }, 175 { "draw", VERBOSE_DRAW }, 176 { "swap", VERBOSE_SWAPBUFFERS } 177 }; 178 GLuint i; 179 180 if (!str) 181 return; 182 183 MESA_VERBOSE = 0x0; 184 for (i = 0; i < Elements(opts); i++) { 185 if (strstr(str, opts[i].name) || strcmp(str, "all") == 0) 186 MESA_VERBOSE |= opts[i].flag; 187 } 188#endif 189} 190 191 192/** 193 * Set debugging flags. When these flags are set, Mesa will do additional 194 * debug checks or actions. 195 * \param str a comma-separated list of keywords 196 */ 197static void 198set_debug_flags(const char *str) 199{ 200#ifdef DEBUG 201 struct option { 202 const char *name; 203 GLbitfield flag; 204 }; 205 static const struct option opts[] = { 206 { "silent", DEBUG_SILENT }, /* turn off debug messages */ 207 { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */ 208 { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE }, 209 { "incomplete_fbo", DEBUG_INCOMPLETE_FBO } 210 }; 211 GLuint i; 212 213 if (!str) 214 return; 215 216 MESA_DEBUG_FLAGS = 0x0; 217 for (i = 0; i < Elements(opts); i++) { 218 if (strstr(str, opts[i].name)) 219 MESA_DEBUG_FLAGS |= opts[i].flag; 220 } 221#endif 222} 223 224 225/** 226 * Initialize debugging variables from env vars. 227 */ 228void 229_mesa_init_debug( struct gl_context *ctx ) 230{ 231 set_debug_flags(_mesa_getenv("MESA_DEBUG")); 232 set_verbose_flags(_mesa_getenv("MESA_VERBOSE")); 233} 234 235 236/* 237 * Write ppm file 238 */ 239static void 240write_ppm(const char *filename, const GLubyte *buffer, int width, int height, 241 int comps, int rcomp, int gcomp, int bcomp, GLboolean invert) 242{ 243 FILE *f = fopen( filename, "w" ); 244 if (f) { 245 int x, y; 246 const GLubyte *ptr = buffer; 247 fprintf(f,"P6\n"); 248 fprintf(f,"# ppm-file created by osdemo.c\n"); 249 fprintf(f,"%i %i\n", width,height); 250 fprintf(f,"255\n"); 251 fclose(f); 252 f = fopen( filename, "ab" ); /* reopen in binary append mode */ 253 for (y=0; y < height; y++) { 254 for (x = 0; x < width; x++) { 255 int yy = invert ? (height - 1 - y) : y; 256 int i = (yy * width + x) * comps; 257 fputc(ptr[i+rcomp], f); /* write red */ 258 fputc(ptr[i+gcomp], f); /* write green */ 259 fputc(ptr[i+bcomp], f); /* write blue */ 260 } 261 } 262 fclose(f); 263 } 264 else { 265 fprintf(stderr, "Unable to create %s in write_ppm()\n", filename); 266 } 267} 268 269 270/** 271 * Write a texture image to a ppm file. 272 * \param face cube face in [0,5] 273 * \param level mipmap level 274 */ 275static void 276write_texture_image(struct gl_texture_object *texObj, 277 GLuint face, GLuint level) 278{ 279 struct gl_texture_image *img = texObj->Image[face][level]; 280 if (img) { 281 GET_CURRENT_CONTEXT(ctx); 282 struct gl_pixelstore_attrib store; 283 GLubyte *buffer; 284 char s[100]; 285 286 buffer = (GLubyte *) malloc(img->Width * img->Height 287 * img->Depth * 4); 288 289 store = ctx->Pack; /* save */ 290 ctx->Pack = ctx->DefaultPacking; 291 292 ctx->Driver.GetTexImage(ctx, GL_RGBA, GL_UNSIGNED_BYTE, buffer, img); 293 294 /* make filename */ 295 _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face); 296 297 printf(" Writing image level %u to %s\n", level, s); 298 write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE); 299 300 ctx->Pack = store; /* restore */ 301 302 free(buffer); 303 } 304} 305 306 307/** 308 * Write renderbuffer image to a ppm file. 309 */ 310void 311_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb) 312{ 313 GET_CURRENT_CONTEXT(ctx); 314 GLubyte *buffer; 315 char s[100]; 316 GLenum format, type; 317 318 if (rb->_BaseFormat == GL_RGB || 319 rb->_BaseFormat == GL_RGBA) { 320 format = GL_RGBA; 321 type = GL_UNSIGNED_BYTE; 322 } 323 else if (rb->_BaseFormat == GL_DEPTH_STENCIL) { 324 format = GL_DEPTH_STENCIL; 325 type = GL_UNSIGNED_INT_24_8; 326 } 327 else { 328 _mesa_debug(NULL, 329 "Unsupported BaseFormat 0x%x in " 330 "_mesa_write_renderbuffer_image()\n", 331 rb->_BaseFormat); 332 return; 333 } 334 335 buffer = (GLubyte *) malloc(rb->Width * rb->Height * 4); 336 337 ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height, 338 format, type, &ctx->DefaultPacking, buffer); 339 340 /* make filename */ 341 _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name); 342 _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name); 343 344 printf(" Writing renderbuffer image to %s\n", s); 345 346 _mesa_debug(NULL, " Writing renderbuffer image to %s\n", s); 347 348 write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE); 349 350 free(buffer); 351} 352 353 354/** How many texture images (mipmap levels, faces) to write to files */ 355#define WRITE_NONE 0 356#define WRITE_ONE 1 357#define WRITE_ALL 2 358 359static GLuint WriteImages; 360 361 362static void 363dump_texture(struct gl_texture_object *texObj, GLuint writeImages) 364{ 365 const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1; 366 GLboolean written = GL_FALSE; 367 GLuint i, j; 368 369 printf("Texture %u\n", texObj->Name); 370 printf(" Target %s\n", tex_target_name(texObj->Target)); 371 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 372 for (j = 0; j < numFaces; j++) { 373 struct gl_texture_image *texImg = texObj->Image[j][i]; 374 if (texImg) { 375 printf(" Face %u level %u: %d x %d x %d, format %s\n", 376 j, i, 377 texImg->Width, texImg->Height, texImg->Depth, 378 _mesa_get_format_name(texImg->TexFormat)); 379 if (writeImages == WRITE_ALL || 380 (writeImages == WRITE_ONE && !written)) { 381 write_texture_image(texObj, j, i); 382 written = GL_TRUE; 383 } 384 } 385 } 386 } 387} 388 389 390/** 391 * Dump a single texture. 392 */ 393void 394_mesa_dump_texture(GLuint texture, GLuint writeImages) 395{ 396 GET_CURRENT_CONTEXT(ctx); 397 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture); 398 if (texObj) { 399 dump_texture(texObj, writeImages); 400 } 401} 402 403 404static void 405dump_texture_cb(GLuint id, void *data, void *userData) 406{ 407 struct gl_texture_object *texObj = (struct gl_texture_object *) data; 408 (void) userData; 409 dump_texture(texObj, WriteImages); 410} 411 412 413/** 414 * Print basic info about all texture objext to stdout. 415 * If dumpImages is true, write PPM of level[0] image to a file. 416 */ 417void 418_mesa_dump_textures(GLuint writeImages) 419{ 420 GET_CURRENT_CONTEXT(ctx); 421 WriteImages = writeImages; 422 _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx); 423} 424 425 426static void 427dump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage) 428{ 429 printf("Renderbuffer %u: %u x %u IntFormat = %s\n", 430 rb->Name, rb->Width, rb->Height, 431 _mesa_lookup_enum_by_nr(rb->InternalFormat)); 432 if (writeImage) { 433 _mesa_write_renderbuffer_image(rb); 434 } 435} 436 437 438static void 439dump_renderbuffer_cb(GLuint id, void *data, void *userData) 440{ 441 const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data; 442 (void) userData; 443 dump_renderbuffer(rb, WriteImages); 444} 445 446 447/** 448 * Print basic info about all renderbuffers to stdout. 449 * If dumpImages is true, write PPM of level[0] image to a file. 450 */ 451void 452_mesa_dump_renderbuffers(GLboolean writeImages) 453{ 454 GET_CURRENT_CONTEXT(ctx); 455 WriteImages = writeImages; 456 _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx); 457} 458 459 460 461void 462_mesa_dump_color_buffer(const char *filename) 463{ 464 GET_CURRENT_CONTEXT(ctx); 465 const GLuint w = ctx->DrawBuffer->Width; 466 const GLuint h = ctx->DrawBuffer->Height; 467 GLubyte *buf; 468 469 buf = (GLubyte *) malloc(w * h * 4); 470 471 _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 472 _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); 473 _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); 474 475 _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf); 476 477 printf("ReadBuffer %p 0x%x DrawBuffer %p 0x%x\n", 478 (void *) ctx->ReadBuffer->_ColorReadBuffer, 479 ctx->ReadBuffer->ColorReadBuffer, 480 (void *) ctx->DrawBuffer->_ColorDrawBuffers[0], 481 ctx->DrawBuffer->ColorDrawBuffer[0]); 482 printf("Writing %d x %d color buffer to %s\n", w, h, filename); 483 write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE); 484 485 _mesa_PopClientAttrib(); 486 487 free(buf); 488} 489 490 491void 492_mesa_dump_depth_buffer(const char *filename) 493{ 494 GET_CURRENT_CONTEXT(ctx); 495 const GLuint w = ctx->DrawBuffer->Width; 496 const GLuint h = ctx->DrawBuffer->Height; 497 GLuint *buf; 498 GLubyte *buf2; 499 GLuint i; 500 501 buf = (GLuint *) malloc(w * h * 4); /* 4 bpp */ 502 buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */ 503 504 _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 505 _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); 506 _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); 507 508 _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf); 509 510 /* spread 24 bits of Z across R, G, B */ 511 for (i = 0; i < w * h; i++) { 512 buf2[i*3+0] = (buf[i] >> 24) & 0xff; 513 buf2[i*3+1] = (buf[i] >> 16) & 0xff; 514 buf2[i*3+2] = (buf[i] >> 8) & 0xff; 515 } 516 517 printf("Writing %d x %d depth buffer to %s\n", w, h, filename); 518 write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE); 519 520 _mesa_PopClientAttrib(); 521 522 free(buf); 523 free(buf2); 524} 525 526 527void 528_mesa_dump_stencil_buffer(const char *filename) 529{ 530 GET_CURRENT_CONTEXT(ctx); 531 const GLuint w = ctx->DrawBuffer->Width; 532 const GLuint h = ctx->DrawBuffer->Height; 533 GLubyte *buf; 534 GLubyte *buf2; 535 GLuint i; 536 537 buf = (GLubyte *) malloc(w * h); /* 1 bpp */ 538 buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */ 539 540 _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 541 _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); 542 _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); 543 544 _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf); 545 546 for (i = 0; i < w * h; i++) { 547 buf2[i*3+0] = buf[i]; 548 buf2[i*3+1] = (buf[i] & 127) * 2; 549 buf2[i*3+2] = (buf[i] - 128) * 2; 550 } 551 552 printf("Writing %d x %d stencil buffer to %s\n", w, h, filename); 553 write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE); 554 555 _mesa_PopClientAttrib(); 556 557 free(buf); 558 free(buf2); 559} 560 561 562void 563_mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h, 564 GLenum format, GLenum type) 565{ 566 GLboolean invert = GL_TRUE; 567 568 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) { 569 write_ppm(filename, image, w, h, 4, 0, 1, 2, invert); 570 } 571 else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) { 572 write_ppm(filename, image, w, h, 4, 2, 1, 0, invert); 573 } 574 else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) { 575 write_ppm(filename, image, w, h, 2, 1, 0, 0, invert); 576 } 577 else if (format == GL_RED && type == GL_UNSIGNED_BYTE) { 578 write_ppm(filename, image, w, h, 1, 0, 0, 0, invert); 579 } 580 else if (format == GL_RGBA && type == GL_FLOAT) { 581 /* convert floats to ubyte */ 582 GLubyte *buf = (GLubyte *) malloc(w * h * 4 * sizeof(GLubyte)); 583 const GLfloat *f = (const GLfloat *) image; 584 GLuint i; 585 for (i = 0; i < w * h * 4; i++) { 586 UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]); 587 } 588 write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert); 589 free(buf); 590 } 591 else if (format == GL_RED && type == GL_FLOAT) { 592 /* convert floats to ubyte */ 593 GLubyte *buf = (GLubyte *) malloc(w * h * sizeof(GLubyte)); 594 const GLfloat *f = (const GLfloat *) image; 595 GLuint i; 596 for (i = 0; i < w * h; i++) { 597 UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]); 598 } 599 write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert); 600 free(buf); 601 } 602 else { 603 _mesa_problem(NULL, 604 "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()", 605 format, type); 606 } 607} 608 609 610/** 611 * Quick and dirty function to "print" a texture to stdout. 612 */ 613void 614_mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img) 615{ 616 const GLint slice = 0; 617 GLint srcRowStride; 618 GLuint i, j, c; 619 GLubyte *data; 620 621 ctx->Driver.MapTextureImage(ctx, img, slice, 622 0, 0, img->Width, img->Height, GL_MAP_READ_BIT, 623 &data, &srcRowStride); 624 625 if (!data) { 626 printf("No texture data\n"); 627 } 628 else { 629 /* XXX add more formats or make into a new format utility function */ 630 switch (img->TexFormat) { 631 case MESA_FORMAT_A8: 632 case MESA_FORMAT_L8: 633 case MESA_FORMAT_I8: 634 c = 1; 635 break; 636 case MESA_FORMAT_AL88: 637 case MESA_FORMAT_AL88_REV: 638 c = 2; 639 break; 640 case MESA_FORMAT_RGB888: 641 case MESA_FORMAT_BGR888: 642 c = 3; 643 break; 644 case MESA_FORMAT_RGBA8888: 645 case MESA_FORMAT_ARGB8888: 646 c = 4; 647 break; 648 default: 649 _mesa_problem(NULL, "error in PrintTexture\n"); 650 return; 651 } 652 653 for (i = 0; i < img->Height; i++) { 654 for (j = 0; j < img->Width; j++) { 655 if (c==1) 656 printf("%02x ", data[0]); 657 else if (c==2) 658 printf("%02x%02x ", data[0], data[1]); 659 else if (c==3) 660 printf("%02x%02x%02x ", data[0], data[1], data[2]); 661 else if (c==4) 662 printf("%02x%02x%02x%02x ", data[0], data[1], data[2], data[3]); 663 data += (srcRowStride - img->Width) * c; 664 } 665 /* XXX use img->ImageStride here */ 666 printf("\n"); 667 668 } 669 } 670 671 ctx->Driver.UnmapTextureImage(ctx, img, slice); 672} 673