debug.c revision 848b8605
1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26848b8605Smrg#include "mtypes.h"
27848b8605Smrg#include "attrib.h"
28848b8605Smrg#include "colormac.h"
29848b8605Smrg#include "enums.h"
30848b8605Smrg#include "formats.h"
31848b8605Smrg#include "hash.h"
32848b8605Smrg#include "imports.h"
33848b8605Smrg#include "debug.h"
34848b8605Smrg#include "get.h"
35848b8605Smrg#include "pixelstore.h"
36848b8605Smrg#include "readpix.h"
37848b8605Smrg#include "texobj.h"
38848b8605Smrg
39848b8605Smrg
40848b8605Smrgstatic const char *
41848b8605Smrgtex_target_name(GLenum tgt)
42848b8605Smrg{
43848b8605Smrg   static const struct {
44848b8605Smrg      GLenum target;
45848b8605Smrg      const char *name;
46848b8605Smrg   } tex_targets[] = {
47848b8605Smrg      { GL_TEXTURE_1D, "GL_TEXTURE_1D" },
48848b8605Smrg      { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
49848b8605Smrg      { GL_TEXTURE_3D, "GL_TEXTURE_3D" },
50848b8605Smrg      { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
51848b8605Smrg      { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" },
52848b8605Smrg      { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" },
53848b8605Smrg      { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" },
54848b8605Smrg      { GL_TEXTURE_CUBE_MAP_ARRAY, "GL_TEXTURE_CUBE_MAP_ARRAY" },
55848b8605Smrg      { GL_TEXTURE_BUFFER, "GL_TEXTURE_BUFFER" },
56848b8605Smrg      { GL_TEXTURE_2D_MULTISAMPLE, "GL_TEXTURE_2D_MULTISAMPLE" },
57848b8605Smrg      { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "GL_TEXTURE_2D_MULTISAMPLE_ARRAY" },
58848b8605Smrg      { GL_TEXTURE_EXTERNAL_OES, "GL_TEXTURE_EXTERNAL_OES" }
59848b8605Smrg   };
60848b8605Smrg   GLuint i;
61848b8605Smrg   STATIC_ASSERT(Elements(tex_targets) == NUM_TEXTURE_TARGETS);
62848b8605Smrg   for (i = 0; i < Elements(tex_targets); i++) {
63848b8605Smrg      if (tex_targets[i].target == tgt)
64848b8605Smrg         return tex_targets[i].name;
65848b8605Smrg   }
66848b8605Smrg   return "UNKNOWN TEX TARGET";
67848b8605Smrg}
68848b8605Smrg
69848b8605Smrg
70848b8605Smrgvoid
71848b8605Smrg_mesa_print_state( const char *msg, GLuint state )
72848b8605Smrg{
73848b8605Smrg   _mesa_debug(NULL,
74848b8605Smrg	   "%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",
75848b8605Smrg	   msg,
76848b8605Smrg	   state,
77848b8605Smrg	   (state & _NEW_MODELVIEW)       ? "ctx->ModelView, " : "",
78848b8605Smrg	   (state & _NEW_PROJECTION)      ? "ctx->Projection, " : "",
79848b8605Smrg	   (state & _NEW_TEXTURE_MATRIX)  ? "ctx->TextureMatrix, " : "",
80848b8605Smrg	   (state & _NEW_COLOR)           ? "ctx->Color, " : "",
81848b8605Smrg	   (state & _NEW_DEPTH)           ? "ctx->Depth, " : "",
82848b8605Smrg	   (state & _NEW_EVAL)            ? "ctx->Eval/EvalMap, " : "",
83848b8605Smrg	   (state & _NEW_FOG)             ? "ctx->Fog, " : "",
84848b8605Smrg	   (state & _NEW_HINT)            ? "ctx->Hint, " : "",
85848b8605Smrg	   (state & _NEW_LIGHT)           ? "ctx->Light, " : "",
86848b8605Smrg	   (state & _NEW_LINE)            ? "ctx->Line, " : "",
87848b8605Smrg	   (state & _NEW_PIXEL)           ? "ctx->Pixel, " : "",
88848b8605Smrg	   (state & _NEW_POINT)           ? "ctx->Point, " : "",
89848b8605Smrg	   (state & _NEW_POLYGON)         ? "ctx->Polygon, " : "",
90848b8605Smrg	   (state & _NEW_POLYGONSTIPPLE)  ? "ctx->PolygonStipple, " : "",
91848b8605Smrg	   (state & _NEW_SCISSOR)         ? "ctx->Scissor, " : "",
92848b8605Smrg	   (state & _NEW_STENCIL)         ? "ctx->Stencil, " : "",
93848b8605Smrg	   (state & _NEW_TEXTURE)         ? "ctx->Texture, " : "",
94848b8605Smrg	   (state & _NEW_TRANSFORM)       ? "ctx->Transform, " : "",
95848b8605Smrg	   (state & _NEW_VIEWPORT)        ? "ctx->Viewport, " : "",
96848b8605Smrg	   (state & _NEW_ARRAY)           ? "ctx->Array, " : "",
97848b8605Smrg	   (state & _NEW_RENDERMODE)      ? "ctx->RenderMode, " : "",
98848b8605Smrg	   (state & _NEW_BUFFERS)         ? "ctx->Visual, ctx->DrawBuffer,, " : "");
99848b8605Smrg}
100848b8605Smrg
101848b8605Smrg
102848b8605Smrg
103848b8605Smrg/**
104848b8605Smrg * Print information about this Mesa version and build options.
105848b8605Smrg */
106848b8605Smrgvoid _mesa_print_info( struct gl_context *ctx )
107848b8605Smrg{
108848b8605Smrg   _mesa_debug(NULL, "Mesa GL_VERSION = %s\n",
109848b8605Smrg	   (char *) _mesa_GetString(GL_VERSION));
110848b8605Smrg   _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n",
111848b8605Smrg	   (char *) _mesa_GetString(GL_RENDERER));
112848b8605Smrg   _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n",
113848b8605Smrg	   (char *) _mesa_GetString(GL_VENDOR));
114848b8605Smrg
115848b8605Smrg   /* use ctx as GL_EXTENSIONS will not work on 3.0 or higher
116848b8605Smrg    * core contexts.
117848b8605Smrg    */
118848b8605Smrg   _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", ctx->Extensions.String);
119848b8605Smrg
120848b8605Smrg#if defined(THREADS)
121848b8605Smrg   _mesa_debug(NULL, "Mesa thread-safe: YES\n");
122848b8605Smrg#else
123848b8605Smrg   _mesa_debug(NULL, "Mesa thread-safe: NO\n");
124848b8605Smrg#endif
125848b8605Smrg#if defined(USE_X86_ASM)
126848b8605Smrg   _mesa_debug(NULL, "Mesa x86-optimized: YES\n");
127848b8605Smrg#else
128848b8605Smrg   _mesa_debug(NULL, "Mesa x86-optimized: NO\n");
129848b8605Smrg#endif
130848b8605Smrg#if defined(USE_SPARC_ASM)
131848b8605Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: YES\n");
132848b8605Smrg#else
133848b8605Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: NO\n");
134848b8605Smrg#endif
135848b8605Smrg}
136848b8605Smrg
137848b8605Smrg
138848b8605Smrg/**
139848b8605Smrg * Set verbose logging flags.  When these flags are set, GL API calls
140848b8605Smrg * in the various categories will be printed to stderr.
141848b8605Smrg * \param str  a comma-separated list of keywords
142848b8605Smrg */
143848b8605Smrgstatic void
144848b8605Smrgset_verbose_flags(const char *str)
145848b8605Smrg{
146848b8605Smrg#ifdef DEBUG
147848b8605Smrg   struct option {
148848b8605Smrg      const char *name;
149848b8605Smrg      GLbitfield flag;
150848b8605Smrg   };
151848b8605Smrg   static const struct option opts[] = {
152848b8605Smrg      { "varray",    VERBOSE_VARRAY },
153848b8605Smrg      { "tex",       VERBOSE_TEXTURE },
154848b8605Smrg      { "mat",       VERBOSE_MATERIAL },
155848b8605Smrg      { "pipe",      VERBOSE_PIPELINE },
156848b8605Smrg      { "driver",    VERBOSE_DRIVER },
157848b8605Smrg      { "state",     VERBOSE_STATE },
158848b8605Smrg      { "api",       VERBOSE_API },
159848b8605Smrg      { "list",      VERBOSE_DISPLAY_LIST },
160848b8605Smrg      { "lighting",  VERBOSE_LIGHTING },
161848b8605Smrg      { "disassem",  VERBOSE_DISASSEM },
162848b8605Smrg      { "draw",      VERBOSE_DRAW },
163848b8605Smrg      { "swap",      VERBOSE_SWAPBUFFERS }
164848b8605Smrg   };
165848b8605Smrg   GLuint i;
166848b8605Smrg
167848b8605Smrg   if (!str)
168848b8605Smrg      return;
169848b8605Smrg
170848b8605Smrg   MESA_VERBOSE = 0x0;
171848b8605Smrg   for (i = 0; i < Elements(opts); i++) {
172848b8605Smrg      if (strstr(str, opts[i].name) || strcmp(str, "all") == 0)
173848b8605Smrg         MESA_VERBOSE |= opts[i].flag;
174848b8605Smrg   }
175848b8605Smrg#endif
176848b8605Smrg}
177848b8605Smrg
178848b8605Smrg
179848b8605Smrg/**
180848b8605Smrg * Set debugging flags.  When these flags are set, Mesa will do additional
181848b8605Smrg * debug checks or actions.
182848b8605Smrg * \param str  a comma-separated list of keywords
183848b8605Smrg */
184848b8605Smrgstatic void
185848b8605Smrgset_debug_flags(const char *str)
186848b8605Smrg{
187848b8605Smrg#ifdef DEBUG
188848b8605Smrg   struct option {
189848b8605Smrg      const char *name;
190848b8605Smrg      GLbitfield flag;
191848b8605Smrg   };
192848b8605Smrg   static const struct option opts[] = {
193848b8605Smrg      { "silent", DEBUG_SILENT }, /* turn off debug messages */
194848b8605Smrg      { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */
195848b8605Smrg      { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE },
196848b8605Smrg      { "incomplete_fbo", DEBUG_INCOMPLETE_FBO }
197848b8605Smrg   };
198848b8605Smrg   GLuint i;
199848b8605Smrg
200848b8605Smrg   if (!str)
201848b8605Smrg      return;
202848b8605Smrg
203848b8605Smrg   MESA_DEBUG_FLAGS = 0x0;
204848b8605Smrg   for (i = 0; i < Elements(opts); i++) {
205848b8605Smrg      if (strstr(str, opts[i].name))
206848b8605Smrg         MESA_DEBUG_FLAGS |= opts[i].flag;
207848b8605Smrg   }
208848b8605Smrg#endif
209848b8605Smrg}
210848b8605Smrg
211848b8605Smrg
212848b8605Smrg/**
213848b8605Smrg * Initialize debugging variables from env vars.
214848b8605Smrg */
215848b8605Smrgvoid
216848b8605Smrg_mesa_init_debug( struct gl_context *ctx )
217848b8605Smrg{
218848b8605Smrg   set_debug_flags(_mesa_getenv("MESA_DEBUG"));
219848b8605Smrg   set_verbose_flags(_mesa_getenv("MESA_VERBOSE"));
220848b8605Smrg}
221848b8605Smrg
222848b8605Smrg
223848b8605Smrg/*
224848b8605Smrg * Write ppm file
225848b8605Smrg */
226848b8605Smrgstatic void
227848b8605Smrgwrite_ppm(const char *filename, const GLubyte *buffer, int width, int height,
228848b8605Smrg          int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
229848b8605Smrg{
230848b8605Smrg   FILE *f = fopen( filename, "w" );
231848b8605Smrg   if (f) {
232848b8605Smrg      int x, y;
233848b8605Smrg      const GLubyte *ptr = buffer;
234848b8605Smrg      fprintf(f,"P6\n");
235848b8605Smrg      fprintf(f,"# ppm-file created by osdemo.c\n");
236848b8605Smrg      fprintf(f,"%i %i\n", width,height);
237848b8605Smrg      fprintf(f,"255\n");
238848b8605Smrg      fclose(f);
239848b8605Smrg      f = fopen( filename, "ab" );  /* reopen in binary append mode */
240848b8605Smrg      for (y=0; y < height; y++) {
241848b8605Smrg         for (x = 0; x < width; x++) {
242848b8605Smrg            int yy = invert ? (height - 1 - y) : y;
243848b8605Smrg            int i = (yy * width + x) * comps;
244848b8605Smrg            fputc(ptr[i+rcomp], f); /* write red */
245848b8605Smrg            fputc(ptr[i+gcomp], f); /* write green */
246848b8605Smrg            fputc(ptr[i+bcomp], f); /* write blue */
247848b8605Smrg         }
248848b8605Smrg      }
249848b8605Smrg      fclose(f);
250848b8605Smrg   }
251848b8605Smrg   else {
252848b8605Smrg      fprintf(stderr, "Unable to create %s in write_ppm()\n", filename);
253848b8605Smrg   }
254848b8605Smrg}
255848b8605Smrg
256848b8605Smrg
257848b8605Smrg/**
258848b8605Smrg * Write a texture image to a ppm file.
259848b8605Smrg * \param face  cube face in [0,5]
260848b8605Smrg * \param level  mipmap level
261848b8605Smrg */
262848b8605Smrgstatic void
263848b8605Smrgwrite_texture_image(struct gl_texture_object *texObj,
264848b8605Smrg                    GLuint face, GLuint level)
265848b8605Smrg{
266848b8605Smrg   struct gl_texture_image *img = texObj->Image[face][level];
267848b8605Smrg   if (img) {
268848b8605Smrg      GET_CURRENT_CONTEXT(ctx);
269848b8605Smrg      struct gl_pixelstore_attrib store;
270848b8605Smrg      GLubyte *buffer;
271848b8605Smrg      char s[100];
272848b8605Smrg
273848b8605Smrg      buffer = malloc(img->Width * img->Height
274848b8605Smrg                                        * img->Depth * 4);
275848b8605Smrg
276848b8605Smrg      store = ctx->Pack; /* save */
277848b8605Smrg      ctx->Pack = ctx->DefaultPacking;
278848b8605Smrg
279848b8605Smrg      ctx->Driver.GetTexImage(ctx, GL_RGBA, GL_UNSIGNED_BYTE, buffer, img);
280848b8605Smrg
281848b8605Smrg      /* make filename */
282848b8605Smrg      _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
283848b8605Smrg
284848b8605Smrg      printf("  Writing image level %u to %s\n", level, s);
285848b8605Smrg      write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
286848b8605Smrg
287848b8605Smrg      ctx->Pack = store; /* restore */
288848b8605Smrg
289848b8605Smrg      free(buffer);
290848b8605Smrg   }
291848b8605Smrg}
292848b8605Smrg
293848b8605Smrg
294848b8605Smrg/**
295848b8605Smrg * Write renderbuffer image to a ppm file.
296848b8605Smrg */
297848b8605Smrgvoid
298848b8605Smrg_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb)
299848b8605Smrg{
300848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
301848b8605Smrg   GLubyte *buffer;
302848b8605Smrg   char s[100];
303848b8605Smrg   GLenum format, type;
304848b8605Smrg
305848b8605Smrg   if (rb->_BaseFormat == GL_RGB ||
306848b8605Smrg       rb->_BaseFormat == GL_RGBA) {
307848b8605Smrg      format = GL_RGBA;
308848b8605Smrg      type = GL_UNSIGNED_BYTE;
309848b8605Smrg   }
310848b8605Smrg   else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
311848b8605Smrg      format = GL_DEPTH_STENCIL;
312848b8605Smrg      type = GL_UNSIGNED_INT_24_8;
313848b8605Smrg   }
314848b8605Smrg   else {
315848b8605Smrg      _mesa_debug(NULL,
316848b8605Smrg                  "Unsupported BaseFormat 0x%x in "
317848b8605Smrg                  "_mesa_write_renderbuffer_image()\n",
318848b8605Smrg                  rb->_BaseFormat);
319848b8605Smrg      return;
320848b8605Smrg   }
321848b8605Smrg
322848b8605Smrg   buffer = malloc(rb->Width * rb->Height * 4);
323848b8605Smrg
324848b8605Smrg   ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
325848b8605Smrg                          format, type, &ctx->DefaultPacking, buffer);
326848b8605Smrg
327848b8605Smrg   /* make filename */
328848b8605Smrg   _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
329848b8605Smrg   _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name);
330848b8605Smrg
331848b8605Smrg   printf("  Writing renderbuffer image to %s\n", s);
332848b8605Smrg
333848b8605Smrg   _mesa_debug(NULL, "  Writing renderbuffer image to %s\n", s);
334848b8605Smrg
335848b8605Smrg   write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
336848b8605Smrg
337848b8605Smrg   free(buffer);
338848b8605Smrg}
339848b8605Smrg
340848b8605Smrg
341848b8605Smrg/** How many texture images (mipmap levels, faces) to write to files */
342848b8605Smrg#define WRITE_NONE 0
343848b8605Smrg#define WRITE_ONE  1
344848b8605Smrg#define WRITE_ALL  2
345848b8605Smrg
346848b8605Smrgstatic GLuint WriteImages;
347848b8605Smrg
348848b8605Smrg
349848b8605Smrgstatic void
350848b8605Smrgdump_texture(struct gl_texture_object *texObj, GLuint writeImages)
351848b8605Smrg{
352848b8605Smrg   const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
353848b8605Smrg   GLboolean written = GL_FALSE;
354848b8605Smrg   GLuint i, j;
355848b8605Smrg
356848b8605Smrg   printf("Texture %u\n", texObj->Name);
357848b8605Smrg   printf("  Target %s\n", tex_target_name(texObj->Target));
358848b8605Smrg   for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
359848b8605Smrg      for (j = 0; j < numFaces; j++) {
360848b8605Smrg         struct gl_texture_image *texImg = texObj->Image[j][i];
361848b8605Smrg         if (texImg) {
362848b8605Smrg            printf("  Face %u level %u: %d x %d x %d, format %s\n",
363848b8605Smrg		   j, i,
364848b8605Smrg		   texImg->Width, texImg->Height, texImg->Depth,
365848b8605Smrg		   _mesa_get_format_name(texImg->TexFormat));
366848b8605Smrg            if (writeImages == WRITE_ALL ||
367848b8605Smrg                (writeImages == WRITE_ONE && !written)) {
368848b8605Smrg               write_texture_image(texObj, j, i);
369848b8605Smrg               written = GL_TRUE;
370848b8605Smrg            }
371848b8605Smrg         }
372848b8605Smrg      }
373848b8605Smrg   }
374848b8605Smrg}
375848b8605Smrg
376848b8605Smrg
377848b8605Smrg/**
378848b8605Smrg * Dump a single texture.
379848b8605Smrg */
380848b8605Smrgvoid
381848b8605Smrg_mesa_dump_texture(GLuint texture, GLuint writeImages)
382848b8605Smrg{
383848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
384848b8605Smrg   struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
385848b8605Smrg   if (texObj) {
386848b8605Smrg      dump_texture(texObj, writeImages);
387848b8605Smrg   }
388848b8605Smrg}
389848b8605Smrg
390848b8605Smrg
391848b8605Smrgstatic void
392848b8605Smrgdump_texture_cb(GLuint id, void *data, void *userData)
393848b8605Smrg{
394848b8605Smrg   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
395848b8605Smrg   (void) userData;
396848b8605Smrg   dump_texture(texObj, WriteImages);
397848b8605Smrg}
398848b8605Smrg
399848b8605Smrg
400848b8605Smrg/**
401848b8605Smrg * Print basic info about all texture objext to stdout.
402848b8605Smrg * If dumpImages is true, write PPM of level[0] image to a file.
403848b8605Smrg */
404848b8605Smrgvoid
405848b8605Smrg_mesa_dump_textures(GLuint writeImages)
406848b8605Smrg{
407848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
408848b8605Smrg   WriteImages = writeImages;
409848b8605Smrg   _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
410848b8605Smrg}
411848b8605Smrg
412848b8605Smrg
413848b8605Smrgstatic void
414848b8605Smrgdump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
415848b8605Smrg{
416848b8605Smrg   printf("Renderbuffer %u: %u x %u  IntFormat = %s\n",
417848b8605Smrg	  rb->Name, rb->Width, rb->Height,
418848b8605Smrg	  _mesa_lookup_enum_by_nr(rb->InternalFormat));
419848b8605Smrg   if (writeImage) {
420848b8605Smrg      _mesa_write_renderbuffer_image(rb);
421848b8605Smrg   }
422848b8605Smrg}
423848b8605Smrg
424848b8605Smrg
425848b8605Smrgstatic void
426848b8605Smrgdump_renderbuffer_cb(GLuint id, void *data, void *userData)
427848b8605Smrg{
428848b8605Smrg   const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
429848b8605Smrg   (void) userData;
430848b8605Smrg   dump_renderbuffer(rb, WriteImages);
431848b8605Smrg}
432848b8605Smrg
433848b8605Smrg
434848b8605Smrg/**
435848b8605Smrg * Print basic info about all renderbuffers to stdout.
436848b8605Smrg * If dumpImages is true, write PPM of level[0] image to a file.
437848b8605Smrg */
438848b8605Smrgvoid
439848b8605Smrg_mesa_dump_renderbuffers(GLboolean writeImages)
440848b8605Smrg{
441848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
442848b8605Smrg   WriteImages = writeImages;
443848b8605Smrg   _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
444848b8605Smrg}
445848b8605Smrg
446848b8605Smrg
447848b8605Smrg
448848b8605Smrgvoid
449848b8605Smrg_mesa_dump_color_buffer(const char *filename)
450848b8605Smrg{
451848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
452848b8605Smrg   const GLuint w = ctx->DrawBuffer->Width;
453848b8605Smrg   const GLuint h = ctx->DrawBuffer->Height;
454848b8605Smrg   GLubyte *buf;
455848b8605Smrg
456848b8605Smrg   buf = malloc(w * h * 4);
457848b8605Smrg
458848b8605Smrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
459848b8605Smrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
460848b8605Smrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
461848b8605Smrg
462848b8605Smrg   _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
463848b8605Smrg
464848b8605Smrg   printf("ReadBuffer %p 0x%x  DrawBuffer %p 0x%x\n",
465848b8605Smrg	  (void *) ctx->ReadBuffer->_ColorReadBuffer,
466848b8605Smrg	  ctx->ReadBuffer->ColorReadBuffer,
467848b8605Smrg	  (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
468848b8605Smrg	  ctx->DrawBuffer->ColorDrawBuffer[0]);
469848b8605Smrg   printf("Writing %d x %d color buffer to %s\n", w, h, filename);
470848b8605Smrg   write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
471848b8605Smrg
472848b8605Smrg   _mesa_PopClientAttrib();
473848b8605Smrg
474848b8605Smrg   free(buf);
475848b8605Smrg}
476848b8605Smrg
477848b8605Smrg
478848b8605Smrgvoid
479848b8605Smrg_mesa_dump_depth_buffer(const char *filename)
480848b8605Smrg{
481848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
482848b8605Smrg   const GLuint w = ctx->DrawBuffer->Width;
483848b8605Smrg   const GLuint h = ctx->DrawBuffer->Height;
484848b8605Smrg   GLuint *buf;
485848b8605Smrg   GLubyte *buf2;
486848b8605Smrg   GLuint i;
487848b8605Smrg
488848b8605Smrg   buf = malloc(w * h * 4);  /* 4 bpp */
489848b8605Smrg   buf2 = malloc(w * h * 3); /* 3 bpp */
490848b8605Smrg
491848b8605Smrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
492848b8605Smrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
493848b8605Smrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
494848b8605Smrg
495848b8605Smrg   _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
496848b8605Smrg
497848b8605Smrg   /* spread 24 bits of Z across R, G, B */
498848b8605Smrg   for (i = 0; i < w * h; i++) {
499848b8605Smrg      buf2[i*3+0] = (buf[i] >> 24) & 0xff;
500848b8605Smrg      buf2[i*3+1] = (buf[i] >> 16) & 0xff;
501848b8605Smrg      buf2[i*3+2] = (buf[i] >>  8) & 0xff;
502848b8605Smrg   }
503848b8605Smrg
504848b8605Smrg   printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
505848b8605Smrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
506848b8605Smrg
507848b8605Smrg   _mesa_PopClientAttrib();
508848b8605Smrg
509848b8605Smrg   free(buf);
510848b8605Smrg   free(buf2);
511848b8605Smrg}
512848b8605Smrg
513848b8605Smrg
514848b8605Smrgvoid
515848b8605Smrg_mesa_dump_stencil_buffer(const char *filename)
516848b8605Smrg{
517848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
518848b8605Smrg   const GLuint w = ctx->DrawBuffer->Width;
519848b8605Smrg   const GLuint h = ctx->DrawBuffer->Height;
520848b8605Smrg   GLubyte *buf;
521848b8605Smrg   GLubyte *buf2;
522848b8605Smrg   GLuint i;
523848b8605Smrg
524848b8605Smrg   buf = malloc(w * h);  /* 1 bpp */
525848b8605Smrg   buf2 = malloc(w * h * 3); /* 3 bpp */
526848b8605Smrg
527848b8605Smrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
528848b8605Smrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
529848b8605Smrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
530848b8605Smrg
531848b8605Smrg   _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
532848b8605Smrg
533848b8605Smrg   for (i = 0; i < w * h; i++) {
534848b8605Smrg      buf2[i*3+0] = buf[i];
535848b8605Smrg      buf2[i*3+1] = (buf[i] & 127) * 2;
536848b8605Smrg      buf2[i*3+2] = (buf[i] - 128) * 2;
537848b8605Smrg   }
538848b8605Smrg
539848b8605Smrg   printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
540848b8605Smrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
541848b8605Smrg
542848b8605Smrg   _mesa_PopClientAttrib();
543848b8605Smrg
544848b8605Smrg   free(buf);
545848b8605Smrg   free(buf2);
546848b8605Smrg}
547848b8605Smrg
548848b8605Smrg
549848b8605Smrgvoid
550848b8605Smrg_mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h,
551848b8605Smrg                 GLenum format, GLenum type)
552848b8605Smrg{
553848b8605Smrg   GLboolean invert = GL_TRUE;
554848b8605Smrg
555848b8605Smrg   if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
556848b8605Smrg      write_ppm(filename, image, w, h, 4, 0, 1, 2, invert);
557848b8605Smrg   }
558848b8605Smrg   else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) {
559848b8605Smrg      write_ppm(filename, image, w, h, 4, 2, 1, 0, invert);
560848b8605Smrg   }
561848b8605Smrg   else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) {
562848b8605Smrg      write_ppm(filename, image, w, h, 2, 1, 0, 0, invert);
563848b8605Smrg   }
564848b8605Smrg   else if (format == GL_RED && type == GL_UNSIGNED_BYTE) {
565848b8605Smrg      write_ppm(filename, image, w, h, 1, 0, 0, 0, invert);
566848b8605Smrg   }
567848b8605Smrg   else if (format == GL_RGBA && type == GL_FLOAT) {
568848b8605Smrg      /* convert floats to ubyte */
569848b8605Smrg      GLubyte *buf = malloc(w * h * 4 * sizeof(GLubyte));
570848b8605Smrg      const GLfloat *f = (const GLfloat *) image;
571848b8605Smrg      GLuint i;
572848b8605Smrg      for (i = 0; i < w * h * 4; i++) {
573848b8605Smrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
574848b8605Smrg      }
575848b8605Smrg      write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert);
576848b8605Smrg      free(buf);
577848b8605Smrg   }
578848b8605Smrg   else if (format == GL_RED && type == GL_FLOAT) {
579848b8605Smrg      /* convert floats to ubyte */
580848b8605Smrg      GLubyte *buf = malloc(w * h * sizeof(GLubyte));
581848b8605Smrg      const GLfloat *f = (const GLfloat *) image;
582848b8605Smrg      GLuint i;
583848b8605Smrg      for (i = 0; i < w * h; i++) {
584848b8605Smrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
585848b8605Smrg      }
586848b8605Smrg      write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert);
587848b8605Smrg      free(buf);
588848b8605Smrg   }
589848b8605Smrg   else {
590848b8605Smrg      _mesa_problem(NULL,
591848b8605Smrg                 "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()",
592848b8605Smrg                 format, type);
593848b8605Smrg   }
594848b8605Smrg}
595848b8605Smrg
596848b8605Smrg
597848b8605Smrg/**
598848b8605Smrg * Quick and dirty function to "print" a texture to stdout.
599848b8605Smrg */
600848b8605Smrgvoid
601848b8605Smrg_mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img)
602848b8605Smrg{
603848b8605Smrg   const GLint slice = 0;
604848b8605Smrg   GLint srcRowStride;
605848b8605Smrg   GLuint i, j, c;
606848b8605Smrg   GLubyte *data;
607848b8605Smrg
608848b8605Smrg   ctx->Driver.MapTextureImage(ctx, img, slice,
609848b8605Smrg                               0, 0, img->Width, img->Height, GL_MAP_READ_BIT,
610848b8605Smrg                               &data, &srcRowStride);
611848b8605Smrg
612848b8605Smrg   if (!data) {
613848b8605Smrg      printf("No texture data\n");
614848b8605Smrg   }
615848b8605Smrg   else {
616848b8605Smrg      /* XXX add more formats or make into a new format utility function */
617848b8605Smrg      switch (img->TexFormat) {
618848b8605Smrg         case MESA_FORMAT_A_UNORM8:
619848b8605Smrg         case MESA_FORMAT_L_UNORM8:
620848b8605Smrg         case MESA_FORMAT_I_UNORM8:
621848b8605Smrg            c = 1;
622848b8605Smrg            break;
623848b8605Smrg         case MESA_FORMAT_L8A8_UNORM:
624848b8605Smrg         case MESA_FORMAT_A8L8_UNORM:
625848b8605Smrg            c = 2;
626848b8605Smrg            break;
627848b8605Smrg         case MESA_FORMAT_BGR_UNORM8:
628848b8605Smrg         case MESA_FORMAT_RGB_UNORM8:
629848b8605Smrg            c = 3;
630848b8605Smrg            break;
631848b8605Smrg         case MESA_FORMAT_A8B8G8R8_UNORM:
632848b8605Smrg         case MESA_FORMAT_B8G8R8A8_UNORM:
633848b8605Smrg            c = 4;
634848b8605Smrg            break;
635848b8605Smrg         default:
636848b8605Smrg            _mesa_problem(NULL, "error in PrintTexture\n");
637848b8605Smrg            return;
638848b8605Smrg      }
639848b8605Smrg
640848b8605Smrg      for (i = 0; i < img->Height; i++) {
641848b8605Smrg         for (j = 0; j < img->Width; j++) {
642848b8605Smrg            if (c==1)
643848b8605Smrg               printf("%02x  ", data[0]);
644848b8605Smrg            else if (c==2)
645848b8605Smrg               printf("%02x%02x  ", data[0], data[1]);
646848b8605Smrg            else if (c==3)
647848b8605Smrg               printf("%02x%02x%02x  ", data[0], data[1], data[2]);
648848b8605Smrg            else if (c==4)
649848b8605Smrg               printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
650848b8605Smrg            data += (srcRowStride - img->Width) * c;
651848b8605Smrg         }
652848b8605Smrg         /* XXX use img->ImageStride here */
653848b8605Smrg         printf("\n");
654848b8605Smrg
655848b8605Smrg      }
656848b8605Smrg   }
657848b8605Smrg
658848b8605Smrg   ctx->Driver.UnmapTextureImage(ctx, img, slice);
659848b8605Smrg}
660