debug.c revision 01e04c3f
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
54a49301eSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
2601e04c3fSmrg#include <stdio.h>
2701e04c3fSmrg#include "errors.h"
287117f1b4Smrg#include "mtypes.h"
294a49301eSmrg#include "attrib.h"
304a49301eSmrg#include "enums.h"
314a49301eSmrg#include "formats.h"
324a49301eSmrg#include "hash.h"
337117f1b4Smrg#include "imports.h"
3401e04c3fSmrg#include "macros.h"
357117f1b4Smrg#include "debug.h"
367117f1b4Smrg#include "get.h"
374a49301eSmrg#include "pixelstore.h"
384a49301eSmrg#include "readpix.h"
394a49301eSmrg#include "texobj.h"
404a49301eSmrg
417117f1b4Smrg
424a49301eSmrgstatic const char *
434a49301eSmrgtex_target_name(GLenum tgt)
444a49301eSmrg{
454a49301eSmrg   static const struct {
464a49301eSmrg      GLenum target;
474a49301eSmrg      const char *name;
484a49301eSmrg   } tex_targets[] = {
494a49301eSmrg      { GL_TEXTURE_1D, "GL_TEXTURE_1D" },
504a49301eSmrg      { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
514a49301eSmrg      { GL_TEXTURE_3D, "GL_TEXTURE_3D" },
524a49301eSmrg      { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
534a49301eSmrg      { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" },
544a49301eSmrg      { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" },
55af69d88dSmrg      { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" },
56af69d88dSmrg      { GL_TEXTURE_CUBE_MAP_ARRAY, "GL_TEXTURE_CUBE_MAP_ARRAY" },
57af69d88dSmrg      { GL_TEXTURE_BUFFER, "GL_TEXTURE_BUFFER" },
58af69d88dSmrg      { GL_TEXTURE_2D_MULTISAMPLE, "GL_TEXTURE_2D_MULTISAMPLE" },
59af69d88dSmrg      { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "GL_TEXTURE_2D_MULTISAMPLE_ARRAY" },
60af69d88dSmrg      { GL_TEXTURE_EXTERNAL_OES, "GL_TEXTURE_EXTERNAL_OES" }
614a49301eSmrg   };
624a49301eSmrg   GLuint i;
6301e04c3fSmrg   STATIC_ASSERT(ARRAY_SIZE(tex_targets) == NUM_TEXTURE_TARGETS);
6401e04c3fSmrg   for (i = 0; i < ARRAY_SIZE(tex_targets); i++) {
654a49301eSmrg      if (tex_targets[i].target == tgt)
664a49301eSmrg         return tex_targets[i].name;
674a49301eSmrg   }
684a49301eSmrg   return "UNKNOWN TEX TARGET";
694a49301eSmrg}
704a49301eSmrg
714a49301eSmrg
727117f1b4Smrgvoid
737117f1b4Smrg_mesa_print_state( const char *msg, GLuint state )
747117f1b4Smrg{
757117f1b4Smrg   _mesa_debug(NULL,
7601e04c3fSmrg	   "%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",
777117f1b4Smrg	   msg,
787117f1b4Smrg	   state,
797117f1b4Smrg	   (state & _NEW_MODELVIEW)       ? "ctx->ModelView, " : "",
807117f1b4Smrg	   (state & _NEW_PROJECTION)      ? "ctx->Projection, " : "",
817117f1b4Smrg	   (state & _NEW_TEXTURE_MATRIX)  ? "ctx->TextureMatrix, " : "",
827117f1b4Smrg	   (state & _NEW_COLOR)           ? "ctx->Color, " : "",
837117f1b4Smrg	   (state & _NEW_DEPTH)           ? "ctx->Depth, " : "",
847117f1b4Smrg	   (state & _NEW_EVAL)            ? "ctx->Eval/EvalMap, " : "",
857117f1b4Smrg	   (state & _NEW_FOG)             ? "ctx->Fog, " : "",
867117f1b4Smrg	   (state & _NEW_HINT)            ? "ctx->Hint, " : "",
877117f1b4Smrg	   (state & _NEW_LIGHT)           ? "ctx->Light, " : "",
887117f1b4Smrg	   (state & _NEW_LINE)            ? "ctx->Line, " : "",
897117f1b4Smrg	   (state & _NEW_PIXEL)           ? "ctx->Pixel, " : "",
907117f1b4Smrg	   (state & _NEW_POINT)           ? "ctx->Point, " : "",
917117f1b4Smrg	   (state & _NEW_POLYGON)         ? "ctx->Polygon, " : "",
927117f1b4Smrg	   (state & _NEW_POLYGONSTIPPLE)  ? "ctx->PolygonStipple, " : "",
937117f1b4Smrg	   (state & _NEW_SCISSOR)         ? "ctx->Scissor, " : "",
943464ebd5Sriastradh	   (state & _NEW_STENCIL)         ? "ctx->Stencil, " : "",
9501e04c3fSmrg	   (state & _NEW_TEXTURE_OBJECT)  ? "ctx->Texture(Object), " : "",
967117f1b4Smrg	   (state & _NEW_TRANSFORM)       ? "ctx->Transform, " : "",
977117f1b4Smrg	   (state & _NEW_VIEWPORT)        ? "ctx->Viewport, " : "",
9801e04c3fSmrg           (state & _NEW_TEXTURE_STATE)   ? "ctx->Texture(State), " : "",
997117f1b4Smrg	   (state & _NEW_ARRAY)           ? "ctx->Array, " : "",
1007117f1b4Smrg	   (state & _NEW_RENDERMODE)      ? "ctx->RenderMode, " : "",
1017117f1b4Smrg	   (state & _NEW_BUFFERS)         ? "ctx->Visual, ctx->DrawBuffer,, " : "");
1027117f1b4Smrg}
1037117f1b4Smrg
1047117f1b4Smrg
1057117f1b4Smrg
1067117f1b4Smrg/**
1077117f1b4Smrg * Print information about this Mesa version and build options.
1087117f1b4Smrg */
109af69d88dSmrgvoid _mesa_print_info( struct gl_context *ctx )
1107117f1b4Smrg{
1117117f1b4Smrg   _mesa_debug(NULL, "Mesa GL_VERSION = %s\n",
1127117f1b4Smrg	   (char *) _mesa_GetString(GL_VERSION));
1137117f1b4Smrg   _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n",
1147117f1b4Smrg	   (char *) _mesa_GetString(GL_RENDERER));
1157117f1b4Smrg   _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n",
1167117f1b4Smrg	   (char *) _mesa_GetString(GL_VENDOR));
117af69d88dSmrg
118af69d88dSmrg   /* use ctx as GL_EXTENSIONS will not work on 3.0 or higher
119af69d88dSmrg    * core contexts.
120af69d88dSmrg    */
121af69d88dSmrg   _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", ctx->Extensions.String);
122af69d88dSmrg
1237117f1b4Smrg#if defined(USE_X86_ASM)
1247117f1b4Smrg   _mesa_debug(NULL, "Mesa x86-optimized: YES\n");
1257117f1b4Smrg#else
1267117f1b4Smrg   _mesa_debug(NULL, "Mesa x86-optimized: NO\n");
1277117f1b4Smrg#endif
1287117f1b4Smrg#if defined(USE_SPARC_ASM)
1297117f1b4Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: YES\n");
1307117f1b4Smrg#else
1317117f1b4Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: NO\n");
1327117f1b4Smrg#endif
1337117f1b4Smrg}
1347117f1b4Smrg
1357117f1b4Smrg
1367117f1b4Smrg/**
137af69d88dSmrg * Set verbose logging flags.  When these flags are set, GL API calls
138af69d88dSmrg * in the various categories will be printed to stderr.
139af69d88dSmrg * \param str  a comma-separated list of keywords
1407117f1b4Smrg */
141af69d88dSmrgstatic void
142af69d88dSmrgset_verbose_flags(const char *str)
1437117f1b4Smrg{
1447117f1b4Smrg#ifdef DEBUG
145af69d88dSmrg   struct option {
146c1f859d4Smrg      const char *name;
147c1f859d4Smrg      GLbitfield flag;
148c1f859d4Smrg   };
149af69d88dSmrg   static const struct option opts[] = {
150c1f859d4Smrg      { "varray",    VERBOSE_VARRAY },
151c1f859d4Smrg      { "tex",       VERBOSE_TEXTURE },
1524a49301eSmrg      { "mat",       VERBOSE_MATERIAL },
153c1f859d4Smrg      { "pipe",      VERBOSE_PIPELINE },
154c1f859d4Smrg      { "driver",    VERBOSE_DRIVER },
155c1f859d4Smrg      { "state",     VERBOSE_STATE },
156c1f859d4Smrg      { "api",       VERBOSE_API },
157c1f859d4Smrg      { "list",      VERBOSE_DISPLAY_LIST },
158c1f859d4Smrg      { "lighting",  VERBOSE_LIGHTING },
159c1f859d4Smrg      { "disassem",  VERBOSE_DISASSEM },
1604a49301eSmrg      { "draw",      VERBOSE_DRAW },
1614a49301eSmrg      { "swap",      VERBOSE_SWAPBUFFERS }
162c1f859d4Smrg   };
163c1f859d4Smrg   GLuint i;
164c1f859d4Smrg
165af69d88dSmrg   if (!str)
166af69d88dSmrg      return;
1677117f1b4Smrg
168af69d88dSmrg   MESA_VERBOSE = 0x0;
16901e04c3fSmrg   for (i = 0; i < ARRAY_SIZE(opts); i++) {
170af69d88dSmrg      if (strstr(str, opts[i].name) || strcmp(str, "all") == 0)
171af69d88dSmrg         MESA_VERBOSE |= opts[i].flag;
1727117f1b4Smrg   }
1737117f1b4Smrg#endif
174af69d88dSmrg}
1757117f1b4Smrg
176af69d88dSmrg
177af69d88dSmrg/**
178af69d88dSmrg * Set debugging flags.  When these flags are set, Mesa will do additional
179af69d88dSmrg * debug checks or actions.
180af69d88dSmrg * \param str  a comma-separated list of keywords
181af69d88dSmrg */
182af69d88dSmrgstatic void
183af69d88dSmrgset_debug_flags(const char *str)
184af69d88dSmrg{
185af69d88dSmrg#ifdef DEBUG
186af69d88dSmrg   struct option {
187af69d88dSmrg      const char *name;
188af69d88dSmrg      GLbitfield flag;
189af69d88dSmrg   };
190af69d88dSmrg   static const struct option opts[] = {
191af69d88dSmrg      { "silent", DEBUG_SILENT }, /* turn off debug messages */
192af69d88dSmrg      { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */
193af69d88dSmrg      { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE },
19401e04c3fSmrg      { "incomplete_fbo", DEBUG_INCOMPLETE_FBO },
19501e04c3fSmrg      { "context", DEBUG_CONTEXT } /* force set GL_CONTEXT_FLAG_DEBUG_BIT flag */
196af69d88dSmrg   };
197af69d88dSmrg   GLuint i;
198af69d88dSmrg
199af69d88dSmrg   if (!str)
200af69d88dSmrg      return;
201af69d88dSmrg
202af69d88dSmrg   MESA_DEBUG_FLAGS = 0x0;
20301e04c3fSmrg   for (i = 0; i < ARRAY_SIZE(opts); i++) {
204af69d88dSmrg      if (strstr(str, opts[i].name))
205af69d88dSmrg         MESA_DEBUG_FLAGS |= opts[i].flag;
206af69d88dSmrg   }
2077117f1b4Smrg#endif
2087117f1b4Smrg}
2097117f1b4Smrg
2107117f1b4Smrg
211af69d88dSmrg/**
212af69d88dSmrg * Initialize debugging variables from env vars.
213af69d88dSmrg */
2147117f1b4Smrgvoid
2153464ebd5Sriastradh_mesa_init_debug( struct gl_context *ctx )
2167117f1b4Smrg{
21701e04c3fSmrg   set_debug_flags(getenv("MESA_DEBUG"));
21801e04c3fSmrg   set_verbose_flags(getenv("MESA_VERBOSE"));
2197117f1b4Smrg}
2207117f1b4Smrg
2214a49301eSmrg
2224a49301eSmrg/*
2234a49301eSmrg * Write ppm file
2244a49301eSmrg */
2254a49301eSmrgstatic void
2264a49301eSmrgwrite_ppm(const char *filename, const GLubyte *buffer, int width, int height,
2274a49301eSmrg          int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
2284a49301eSmrg{
2294a49301eSmrg   FILE *f = fopen( filename, "w" );
2304a49301eSmrg   if (f) {
2314a49301eSmrg      int x, y;
2324a49301eSmrg      const GLubyte *ptr = buffer;
2334a49301eSmrg      fprintf(f,"P6\n");
2344a49301eSmrg      fprintf(f,"# ppm-file created by osdemo.c\n");
2354a49301eSmrg      fprintf(f,"%i %i\n", width,height);
2364a49301eSmrg      fprintf(f,"255\n");
2374a49301eSmrg      fclose(f);
2384a49301eSmrg      f = fopen( filename, "ab" );  /* reopen in binary append mode */
23901e04c3fSmrg      if (!f) {
24001e04c3fSmrg         fprintf(stderr, "Error while reopening %s in write_ppm()\n",
24101e04c3fSmrg                 filename);
24201e04c3fSmrg         return;
24301e04c3fSmrg      }
2444a49301eSmrg      for (y=0; y < height; y++) {
2454a49301eSmrg         for (x = 0; x < width; x++) {
2464a49301eSmrg            int yy = invert ? (height - 1 - y) : y;
2474a49301eSmrg            int i = (yy * width + x) * comps;
2484a49301eSmrg            fputc(ptr[i+rcomp], f); /* write red */
2494a49301eSmrg            fputc(ptr[i+gcomp], f); /* write green */
2504a49301eSmrg            fputc(ptr[i+bcomp], f); /* write blue */
2514a49301eSmrg         }
2524a49301eSmrg      }
2534a49301eSmrg      fclose(f);
2544a49301eSmrg   }
2553464ebd5Sriastradh   else {
2563464ebd5Sriastradh      fprintf(stderr, "Unable to create %s in write_ppm()\n", filename);
2573464ebd5Sriastradh   }
2584a49301eSmrg}
2594a49301eSmrg
2604a49301eSmrg
2614a49301eSmrg/**
2624a49301eSmrg * Write a texture image to a ppm file.
2634a49301eSmrg * \param face  cube face in [0,5]
2644a49301eSmrg * \param level  mipmap level
2654a49301eSmrg */
2664a49301eSmrgstatic void
2674a49301eSmrgwrite_texture_image(struct gl_texture_object *texObj,
2684a49301eSmrg                    GLuint face, GLuint level)
2694a49301eSmrg{
2704a49301eSmrg   struct gl_texture_image *img = texObj->Image[face][level];
2714a49301eSmrg   if (img) {
2724a49301eSmrg      GET_CURRENT_CONTEXT(ctx);
2734a49301eSmrg      struct gl_pixelstore_attrib store;
2744a49301eSmrg      GLubyte *buffer;
2754a49301eSmrg      char s[100];
2764a49301eSmrg
277af69d88dSmrg      buffer = malloc(img->Width * img->Height
2784a49301eSmrg                                        * img->Depth * 4);
2794a49301eSmrg
2804a49301eSmrg      store = ctx->Pack; /* save */
2814a49301eSmrg      ctx->Pack = ctx->DefaultPacking;
2824a49301eSmrg
28301e04c3fSmrg      ctx->Driver.GetTexSubImage(ctx,
28401e04c3fSmrg                                 0, 0, 0, img->Width, img->Height, img->Depth,
28501e04c3fSmrg                                 GL_RGBA, GL_UNSIGNED_BYTE, buffer, img);
2864a49301eSmrg
2874a49301eSmrg      /* make filename */
2883464ebd5Sriastradh      _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
2894a49301eSmrg
290cdc920a0Smrg      printf("  Writing image level %u to %s\n", level, s);
2914a49301eSmrg      write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
2924a49301eSmrg
2934a49301eSmrg      ctx->Pack = store; /* restore */
2944a49301eSmrg
295cdc920a0Smrg      free(buffer);
2964a49301eSmrg   }
2974a49301eSmrg}
2984a49301eSmrg
2994a49301eSmrg
3004a49301eSmrg/**
3014a49301eSmrg * Write renderbuffer image to a ppm file.
3024a49301eSmrg */
3033464ebd5Sriastradhvoid
3043464ebd5Sriastradh_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb)
3054a49301eSmrg{
3064a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
3074a49301eSmrg   GLubyte *buffer;
3084a49301eSmrg   char s[100];
3094a49301eSmrg   GLenum format, type;
3104a49301eSmrg
3114a49301eSmrg   if (rb->_BaseFormat == GL_RGB ||
3124a49301eSmrg       rb->_BaseFormat == GL_RGBA) {
3134a49301eSmrg      format = GL_RGBA;
3144a49301eSmrg      type = GL_UNSIGNED_BYTE;
3154a49301eSmrg   }
3164a49301eSmrg   else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
3174a49301eSmrg      format = GL_DEPTH_STENCIL;
3184a49301eSmrg      type = GL_UNSIGNED_INT_24_8;
3194a49301eSmrg   }
3204a49301eSmrg   else {
3213464ebd5Sriastradh      _mesa_debug(NULL,
3223464ebd5Sriastradh                  "Unsupported BaseFormat 0x%x in "
3233464ebd5Sriastradh                  "_mesa_write_renderbuffer_image()\n",
3243464ebd5Sriastradh                  rb->_BaseFormat);
3254a49301eSmrg      return;
3264a49301eSmrg   }
3274a49301eSmrg
328af69d88dSmrg   buffer = malloc(rb->Width * rb->Height * 4);
3294a49301eSmrg
3304a49301eSmrg   ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
3314a49301eSmrg                          format, type, &ctx->DefaultPacking, buffer);
3324a49301eSmrg
3334a49301eSmrg   /* make filename */
3343464ebd5Sriastradh   _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
3353464ebd5Sriastradh   _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name);
3364a49301eSmrg
337cdc920a0Smrg   printf("  Writing renderbuffer image to %s\n", s);
3383464ebd5Sriastradh
3393464ebd5Sriastradh   _mesa_debug(NULL, "  Writing renderbuffer image to %s\n", s);
3403464ebd5Sriastradh
3414a49301eSmrg   write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
3424a49301eSmrg
343cdc920a0Smrg   free(buffer);
3444a49301eSmrg}
3454a49301eSmrg
3464a49301eSmrg
3474a49301eSmrg/** How many texture images (mipmap levels, faces) to write to files */
3484a49301eSmrg#define WRITE_NONE 0
3494a49301eSmrg#define WRITE_ONE  1
3504a49301eSmrg#define WRITE_ALL  2
3514a49301eSmrg
3524a49301eSmrgstatic GLuint WriteImages;
3534a49301eSmrg
3544a49301eSmrg
3554a49301eSmrgstatic void
3564a49301eSmrgdump_texture(struct gl_texture_object *texObj, GLuint writeImages)
3574a49301eSmrg{
3584a49301eSmrg   const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
3594a49301eSmrg   GLboolean written = GL_FALSE;
3604a49301eSmrg   GLuint i, j;
3614a49301eSmrg
362cdc920a0Smrg   printf("Texture %u\n", texObj->Name);
363cdc920a0Smrg   printf("  Target %s\n", tex_target_name(texObj->Target));
3644a49301eSmrg   for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
3654a49301eSmrg      for (j = 0; j < numFaces; j++) {
3664a49301eSmrg         struct gl_texture_image *texImg = texObj->Image[j][i];
3674a49301eSmrg         if (texImg) {
368af69d88dSmrg            printf("  Face %u level %u: %d x %d x %d, format %s\n",
369cdc920a0Smrg		   j, i,
370cdc920a0Smrg		   texImg->Width, texImg->Height, texImg->Depth,
371af69d88dSmrg		   _mesa_get_format_name(texImg->TexFormat));
3724a49301eSmrg            if (writeImages == WRITE_ALL ||
3734a49301eSmrg                (writeImages == WRITE_ONE && !written)) {
3744a49301eSmrg               write_texture_image(texObj, j, i);
3754a49301eSmrg               written = GL_TRUE;
3764a49301eSmrg            }
3774a49301eSmrg         }
3784a49301eSmrg      }
3794a49301eSmrg   }
3804a49301eSmrg}
3814a49301eSmrg
3824a49301eSmrg
3834a49301eSmrg/**
3844a49301eSmrg * Dump a single texture.
3854a49301eSmrg */
3864a49301eSmrgvoid
3874a49301eSmrg_mesa_dump_texture(GLuint texture, GLuint writeImages)
3884a49301eSmrg{
3894a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
3904a49301eSmrg   struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
3914a49301eSmrg   if (texObj) {
3924a49301eSmrg      dump_texture(texObj, writeImages);
3934a49301eSmrg   }
3944a49301eSmrg}
3954a49301eSmrg
3964a49301eSmrg
3974a49301eSmrgstatic void
3984a49301eSmrgdump_texture_cb(GLuint id, void *data, void *userData)
3994a49301eSmrg{
4004a49301eSmrg   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
4014a49301eSmrg   (void) userData;
4024a49301eSmrg   dump_texture(texObj, WriteImages);
4034a49301eSmrg}
4044a49301eSmrg
4054a49301eSmrg
4064a49301eSmrg/**
4074a49301eSmrg * Print basic info about all texture objext to stdout.
4084a49301eSmrg * If dumpImages is true, write PPM of level[0] image to a file.
4094a49301eSmrg */
4104a49301eSmrgvoid
4114a49301eSmrg_mesa_dump_textures(GLuint writeImages)
4124a49301eSmrg{
4134a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4144a49301eSmrg   WriteImages = writeImages;
4154a49301eSmrg   _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
4164a49301eSmrg}
4174a49301eSmrg
4184a49301eSmrg
4194a49301eSmrgstatic void
4204a49301eSmrgdump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
4214a49301eSmrg{
422cdc920a0Smrg   printf("Renderbuffer %u: %u x %u  IntFormat = %s\n",
423cdc920a0Smrg	  rb->Name, rb->Width, rb->Height,
42401e04c3fSmrg	  _mesa_enum_to_string(rb->InternalFormat));
4254a49301eSmrg   if (writeImage) {
4263464ebd5Sriastradh      _mesa_write_renderbuffer_image(rb);
4274a49301eSmrg   }
4284a49301eSmrg}
4294a49301eSmrg
4304a49301eSmrg
4314a49301eSmrgstatic void
4324a49301eSmrgdump_renderbuffer_cb(GLuint id, void *data, void *userData)
4334a49301eSmrg{
4344a49301eSmrg   const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
4354a49301eSmrg   (void) userData;
4364a49301eSmrg   dump_renderbuffer(rb, WriteImages);
4374a49301eSmrg}
4384a49301eSmrg
4394a49301eSmrg
4404a49301eSmrg/**
4414a49301eSmrg * Print basic info about all renderbuffers to stdout.
4424a49301eSmrg * If dumpImages is true, write PPM of level[0] image to a file.
4434a49301eSmrg */
4444a49301eSmrgvoid
4454a49301eSmrg_mesa_dump_renderbuffers(GLboolean writeImages)
4464a49301eSmrg{
4474a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4484a49301eSmrg   WriteImages = writeImages;
4494a49301eSmrg   _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
4504a49301eSmrg}
4514a49301eSmrg
4524a49301eSmrg
4534a49301eSmrg
4544a49301eSmrgvoid
4554a49301eSmrg_mesa_dump_color_buffer(const char *filename)
4564a49301eSmrg{
4574a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4584a49301eSmrg   const GLuint w = ctx->DrawBuffer->Width;
4594a49301eSmrg   const GLuint h = ctx->DrawBuffer->Height;
4604a49301eSmrg   GLubyte *buf;
4614a49301eSmrg
462af69d88dSmrg   buf = malloc(w * h * 4);
4634a49301eSmrg
4644a49301eSmrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
4654a49301eSmrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
4664a49301eSmrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
4674a49301eSmrg
4684a49301eSmrg   _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
4694a49301eSmrg
470cdc920a0Smrg   printf("ReadBuffer %p 0x%x  DrawBuffer %p 0x%x\n",
471cdc920a0Smrg	  (void *) ctx->ReadBuffer->_ColorReadBuffer,
472cdc920a0Smrg	  ctx->ReadBuffer->ColorReadBuffer,
473cdc920a0Smrg	  (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
474cdc920a0Smrg	  ctx->DrawBuffer->ColorDrawBuffer[0]);
475cdc920a0Smrg   printf("Writing %d x %d color buffer to %s\n", w, h, filename);
4764a49301eSmrg   write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
4774a49301eSmrg
4784a49301eSmrg   _mesa_PopClientAttrib();
4794a49301eSmrg
480cdc920a0Smrg   free(buf);
4814a49301eSmrg}
4824a49301eSmrg
4834a49301eSmrg
4844a49301eSmrgvoid
4854a49301eSmrg_mesa_dump_depth_buffer(const char *filename)
4864a49301eSmrg{
4874a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4884a49301eSmrg   const GLuint w = ctx->DrawBuffer->Width;
4894a49301eSmrg   const GLuint h = ctx->DrawBuffer->Height;
4904a49301eSmrg   GLuint *buf;
4914a49301eSmrg   GLubyte *buf2;
4924a49301eSmrg   GLuint i;
4934a49301eSmrg
494af69d88dSmrg   buf = malloc(w * h * 4);  /* 4 bpp */
495af69d88dSmrg   buf2 = malloc(w * h * 3); /* 3 bpp */
4964a49301eSmrg
4974a49301eSmrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
4984a49301eSmrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
4994a49301eSmrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
5004a49301eSmrg
5014a49301eSmrg   _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
5024a49301eSmrg
5034a49301eSmrg   /* spread 24 bits of Z across R, G, B */
5044a49301eSmrg   for (i = 0; i < w * h; i++) {
5054a49301eSmrg      buf2[i*3+0] = (buf[i] >> 24) & 0xff;
5064a49301eSmrg      buf2[i*3+1] = (buf[i] >> 16) & 0xff;
5074a49301eSmrg      buf2[i*3+2] = (buf[i] >>  8) & 0xff;
5084a49301eSmrg   }
5094a49301eSmrg
510cdc920a0Smrg   printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
5114a49301eSmrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
5124a49301eSmrg
5134a49301eSmrg   _mesa_PopClientAttrib();
5144a49301eSmrg
515cdc920a0Smrg   free(buf);
516cdc920a0Smrg   free(buf2);
5174a49301eSmrg}
5184a49301eSmrg
5194a49301eSmrg
5204a49301eSmrgvoid
5214a49301eSmrg_mesa_dump_stencil_buffer(const char *filename)
5224a49301eSmrg{
5234a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
5244a49301eSmrg   const GLuint w = ctx->DrawBuffer->Width;
5254a49301eSmrg   const GLuint h = ctx->DrawBuffer->Height;
5264a49301eSmrg   GLubyte *buf;
5274a49301eSmrg   GLubyte *buf2;
5284a49301eSmrg   GLuint i;
5294a49301eSmrg
530af69d88dSmrg   buf = malloc(w * h);  /* 1 bpp */
531af69d88dSmrg   buf2 = malloc(w * h * 3); /* 3 bpp */
5324a49301eSmrg
5334a49301eSmrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
5344a49301eSmrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
5354a49301eSmrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
5364a49301eSmrg
5374a49301eSmrg   _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
5384a49301eSmrg
5394a49301eSmrg   for (i = 0; i < w * h; i++) {
5404a49301eSmrg      buf2[i*3+0] = buf[i];
5414a49301eSmrg      buf2[i*3+1] = (buf[i] & 127) * 2;
5424a49301eSmrg      buf2[i*3+2] = (buf[i] - 128) * 2;
5434a49301eSmrg   }
5444a49301eSmrg
545cdc920a0Smrg   printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
5464a49301eSmrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
5474a49301eSmrg
5484a49301eSmrg   _mesa_PopClientAttrib();
5494a49301eSmrg
550cdc920a0Smrg   free(buf);
551cdc920a0Smrg   free(buf2);
5524a49301eSmrg}
5534a49301eSmrg
5544a49301eSmrg
5553464ebd5Sriastradhvoid
5563464ebd5Sriastradh_mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h,
5573464ebd5Sriastradh                 GLenum format, GLenum type)
5583464ebd5Sriastradh{
5593464ebd5Sriastradh   GLboolean invert = GL_TRUE;
5603464ebd5Sriastradh
5613464ebd5Sriastradh   if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
5623464ebd5Sriastradh      write_ppm(filename, image, w, h, 4, 0, 1, 2, invert);
5633464ebd5Sriastradh   }
5643464ebd5Sriastradh   else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) {
5653464ebd5Sriastradh      write_ppm(filename, image, w, h, 4, 2, 1, 0, invert);
5663464ebd5Sriastradh   }
5673464ebd5Sriastradh   else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) {
5683464ebd5Sriastradh      write_ppm(filename, image, w, h, 2, 1, 0, 0, invert);
5693464ebd5Sriastradh   }
570af69d88dSmrg   else if (format == GL_RED && type == GL_UNSIGNED_BYTE) {
571af69d88dSmrg      write_ppm(filename, image, w, h, 1, 0, 0, 0, invert);
572af69d88dSmrg   }
573af69d88dSmrg   else if (format == GL_RGBA && type == GL_FLOAT) {
574af69d88dSmrg      /* convert floats to ubyte */
575af69d88dSmrg      GLubyte *buf = malloc(w * h * 4 * sizeof(GLubyte));
576af69d88dSmrg      const GLfloat *f = (const GLfloat *) image;
577af69d88dSmrg      GLuint i;
578af69d88dSmrg      for (i = 0; i < w * h * 4; i++) {
579af69d88dSmrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
580af69d88dSmrg      }
581af69d88dSmrg      write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert);
582af69d88dSmrg      free(buf);
583af69d88dSmrg   }
584af69d88dSmrg   else if (format == GL_RED && type == GL_FLOAT) {
585af69d88dSmrg      /* convert floats to ubyte */
586af69d88dSmrg      GLubyte *buf = malloc(w * h * sizeof(GLubyte));
587af69d88dSmrg      const GLfloat *f = (const GLfloat *) image;
588af69d88dSmrg      GLuint i;
589af69d88dSmrg      for (i = 0; i < w * h; i++) {
590af69d88dSmrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
591af69d88dSmrg      }
592af69d88dSmrg      write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert);
593af69d88dSmrg      free(buf);
594af69d88dSmrg   }
5953464ebd5Sriastradh   else {
596af69d88dSmrg      _mesa_problem(NULL,
597af69d88dSmrg                 "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()",
598af69d88dSmrg                 format, type);
5993464ebd5Sriastradh   }
6003464ebd5Sriastradh}
6013464ebd5Sriastradh
6023464ebd5Sriastradh
6034a49301eSmrg/**
6044a49301eSmrg * Quick and dirty function to "print" a texture to stdout.
6054a49301eSmrg */
6064a49301eSmrgvoid
607af69d88dSmrg_mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img)
6084a49301eSmrg{
609af69d88dSmrg   const GLint slice = 0;
610af69d88dSmrg   GLint srcRowStride;
6114a49301eSmrg   GLuint i, j, c;
612af69d88dSmrg   GLubyte *data;
613af69d88dSmrg
614af69d88dSmrg   ctx->Driver.MapTextureImage(ctx, img, slice,
615af69d88dSmrg                               0, 0, img->Width, img->Height, GL_MAP_READ_BIT,
616af69d88dSmrg                               &data, &srcRowStride);
6174a49301eSmrg
6184a49301eSmrg   if (!data) {
619cdc920a0Smrg      printf("No texture data\n");
6204a49301eSmrg   }
621af69d88dSmrg   else {
622af69d88dSmrg      /* XXX add more formats or make into a new format utility function */
623af69d88dSmrg      switch (img->TexFormat) {
624af69d88dSmrg         case MESA_FORMAT_A_UNORM8:
625af69d88dSmrg         case MESA_FORMAT_L_UNORM8:
626af69d88dSmrg         case MESA_FORMAT_I_UNORM8:
627af69d88dSmrg            c = 1;
628af69d88dSmrg            break;
629af69d88dSmrg         case MESA_FORMAT_L8A8_UNORM:
630af69d88dSmrg         case MESA_FORMAT_A8L8_UNORM:
631af69d88dSmrg            c = 2;
632af69d88dSmrg            break;
633af69d88dSmrg         case MESA_FORMAT_BGR_UNORM8:
634af69d88dSmrg         case MESA_FORMAT_RGB_UNORM8:
635af69d88dSmrg            c = 3;
636af69d88dSmrg            break;
637af69d88dSmrg         case MESA_FORMAT_A8B8G8R8_UNORM:
638af69d88dSmrg         case MESA_FORMAT_B8G8R8A8_UNORM:
639af69d88dSmrg            c = 4;
640af69d88dSmrg            break;
641af69d88dSmrg         default:
642af69d88dSmrg            _mesa_problem(NULL, "error in PrintTexture\n");
643af69d88dSmrg            return;
644af69d88dSmrg      }
6454a49301eSmrg
646af69d88dSmrg      for (i = 0; i < img->Height; i++) {
647af69d88dSmrg         for (j = 0; j < img->Width; j++) {
648af69d88dSmrg            if (c==1)
649af69d88dSmrg               printf("%02x  ", data[0]);
650af69d88dSmrg            else if (c==2)
651af69d88dSmrg               printf("%02x%02x  ", data[0], data[1]);
652af69d88dSmrg            else if (c==3)
653af69d88dSmrg               printf("%02x%02x%02x  ", data[0], data[1], data[2]);
654af69d88dSmrg            else if (c==4)
655af69d88dSmrg               printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
656af69d88dSmrg            data += (srcRowStride - img->Width) * c;
657af69d88dSmrg         }
658af69d88dSmrg         /* XXX use img->ImageStride here */
659af69d88dSmrg         printf("\n");
6604a49301eSmrg
6614a49301eSmrg      }
6624a49301eSmrg   }
663af69d88dSmrg
664af69d88dSmrg   ctx->Driver.UnmapTextureImage(ctx, img, slice);
6654a49301eSmrg}
666