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