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