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