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 40 static const char * 41 tex_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 65 void 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 99 void 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 */ 123 void _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 */ 156 static void 157 set_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 */ 197 static void 198 set_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 */ 228 void 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 */ 239 static void 240 write_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 */ 275 static void 276 write_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 */ 310 void 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 359 static GLuint WriteImages; 360 361 362 static void 363 dump_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 */ 393 void 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 404 static void 405 dump_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 */ 417 void 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 426 static void 427 dump_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 438 static void 439 dump_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 */ 451 void 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 461 void 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 491 void 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 527 void 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 562 void 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 */ 613 void 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