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"
337ec681f3Smrg
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,
76a8bb7a65Smaya	   "%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",
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_FOG)             ? "ctx->Fog, " : "",
857117f1b4Smrg	   (state & _NEW_HINT)            ? "ctx->Hint, " : "",
867ec681f3Smrg	   (state & _NEW_LIGHT_CONSTANTS) ? "ctx->Light(Constants), " : "",
877ec681f3Smrg           (state & _NEW_LIGHT_STATE)     ? "ctx->Light(State), " : "",
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_RENDERMODE)      ? "ctx->RenderMode, " : "",
1007117f1b4Smrg	   (state & _NEW_BUFFERS)         ? "ctx->Visual, ctx->DrawBuffer,, " : "");
1017117f1b4Smrg}
1027117f1b4Smrg
1037117f1b4Smrg
1047117f1b4Smrg
1057117f1b4Smrg/**
1067117f1b4Smrg * Print information about this Mesa version and build options.
1077117f1b4Smrg */
108af69d88dSmrgvoid _mesa_print_info( struct gl_context *ctx )
1097117f1b4Smrg{
1107117f1b4Smrg   _mesa_debug(NULL, "Mesa GL_VERSION = %s\n",
1117117f1b4Smrg	   (char *) _mesa_GetString(GL_VERSION));
1127117f1b4Smrg   _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n",
1137117f1b4Smrg	   (char *) _mesa_GetString(GL_RENDERER));
1147117f1b4Smrg   _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n",
1157117f1b4Smrg	   (char *) _mesa_GetString(GL_VENDOR));
116af69d88dSmrg
117af69d88dSmrg   /* use ctx as GL_EXTENSIONS will not work on 3.0 or higher
118af69d88dSmrg    * core contexts.
119af69d88dSmrg    */
120af69d88dSmrg   _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", ctx->Extensions.String);
121af69d88dSmrg
1227117f1b4Smrg#if defined(USE_X86_ASM)
1237117f1b4Smrg   _mesa_debug(NULL, "Mesa x86-optimized: YES\n");
1247117f1b4Smrg#else
1257117f1b4Smrg   _mesa_debug(NULL, "Mesa x86-optimized: NO\n");
1267117f1b4Smrg#endif
1277117f1b4Smrg#if defined(USE_SPARC_ASM)
1287117f1b4Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: YES\n");
1297117f1b4Smrg#else
1307117f1b4Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: NO\n");
1317117f1b4Smrg#endif
1327117f1b4Smrg}
1337117f1b4Smrg
1347117f1b4Smrg
1357117f1b4Smrg/**
136af69d88dSmrg * Set verbose logging flags.  When these flags are set, GL API calls
137af69d88dSmrg * in the various categories will be printed to stderr.
138af69d88dSmrg * \param str  a comma-separated list of keywords
1397117f1b4Smrg */
140af69d88dSmrgstatic void
141af69d88dSmrgset_verbose_flags(const char *str)
1427117f1b4Smrg{
1437ec681f3Smrg#ifndef NDEBUG
144af69d88dSmrg   struct option {
145c1f859d4Smrg      const char *name;
146c1f859d4Smrg      GLbitfield flag;
147c1f859d4Smrg   };
148af69d88dSmrg   static const struct option opts[] = {
149c1f859d4Smrg      { "varray",    VERBOSE_VARRAY },
150c1f859d4Smrg      { "tex",       VERBOSE_TEXTURE },
1514a49301eSmrg      { "mat",       VERBOSE_MATERIAL },
152c1f859d4Smrg      { "pipe",      VERBOSE_PIPELINE },
153c1f859d4Smrg      { "driver",    VERBOSE_DRIVER },
154c1f859d4Smrg      { "state",     VERBOSE_STATE },
155c1f859d4Smrg      { "api",       VERBOSE_API },
156c1f859d4Smrg      { "list",      VERBOSE_DISPLAY_LIST },
157c1f859d4Smrg      { "lighting",  VERBOSE_LIGHTING },
158c1f859d4Smrg      { "disassem",  VERBOSE_DISASSEM },
1594a49301eSmrg      { "swap",      VERBOSE_SWAPBUFFERS }
160c1f859d4Smrg   };
161c1f859d4Smrg   GLuint i;
162c1f859d4Smrg
163af69d88dSmrg   if (!str)
164af69d88dSmrg      return;
1657117f1b4Smrg
166af69d88dSmrg   MESA_VERBOSE = 0x0;
16701e04c3fSmrg   for (i = 0; i < ARRAY_SIZE(opts); i++) {
168af69d88dSmrg      if (strstr(str, opts[i].name) || strcmp(str, "all") == 0)
169af69d88dSmrg         MESA_VERBOSE |= opts[i].flag;
1707117f1b4Smrg   }
1717117f1b4Smrg#endif
172af69d88dSmrg}
1737117f1b4Smrg
174af69d88dSmrg
175af69d88dSmrg/**
176af69d88dSmrg * Set debugging flags.  When these flags are set, Mesa will do additional
177af69d88dSmrg * debug checks or actions.
178af69d88dSmrg * \param str  a comma-separated list of keywords
179af69d88dSmrg */
180af69d88dSmrgstatic void
181af69d88dSmrgset_debug_flags(const char *str)
182af69d88dSmrg{
1837ec681f3Smrg#ifndef NDEBUG
184af69d88dSmrg   struct option {
185af69d88dSmrg      const char *name;
186af69d88dSmrg      GLbitfield flag;
187af69d88dSmrg   };
188af69d88dSmrg   static const struct option opts[] = {
189af69d88dSmrg      { "silent", DEBUG_SILENT }, /* turn off debug messages */
190af69d88dSmrg      { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */
191af69d88dSmrg      { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE },
19201e04c3fSmrg      { "incomplete_fbo", DEBUG_INCOMPLETE_FBO },
19301e04c3fSmrg      { "context", DEBUG_CONTEXT } /* force set GL_CONTEXT_FLAG_DEBUG_BIT flag */
194af69d88dSmrg   };
195af69d88dSmrg   GLuint i;
196af69d88dSmrg
197af69d88dSmrg   if (!str)
198af69d88dSmrg      return;
199af69d88dSmrg
200af69d88dSmrg   MESA_DEBUG_FLAGS = 0x0;
20101e04c3fSmrg   for (i = 0; i < ARRAY_SIZE(opts); i++) {
202af69d88dSmrg      if (strstr(str, opts[i].name))
203af69d88dSmrg         MESA_DEBUG_FLAGS |= opts[i].flag;
204af69d88dSmrg   }
2057117f1b4Smrg#endif
2067117f1b4Smrg}
2077117f1b4Smrg
2087117f1b4Smrg
209af69d88dSmrg/**
210af69d88dSmrg * Initialize debugging variables from env vars.
211af69d88dSmrg */
2127ec681f3Smrgvoid
2133464ebd5Sriastradh_mesa_init_debug( struct gl_context *ctx )
2147117f1b4Smrg{
21501e04c3fSmrg   set_debug_flags(getenv("MESA_DEBUG"));
21601e04c3fSmrg   set_verbose_flags(getenv("MESA_VERBOSE"));
2177117f1b4Smrg}
2187117f1b4Smrg
2194a49301eSmrg
2204a49301eSmrg/*
2214a49301eSmrg * Write ppm file
2224a49301eSmrg */
2234a49301eSmrgstatic void
2244a49301eSmrgwrite_ppm(const char *filename, const GLubyte *buffer, int width, int height,
2254a49301eSmrg          int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
2264a49301eSmrg{
2274a49301eSmrg   FILE *f = fopen( filename, "w" );
2284a49301eSmrg   if (f) {
2294a49301eSmrg      int x, y;
2304a49301eSmrg      const GLubyte *ptr = buffer;
2314a49301eSmrg      fprintf(f,"P6\n");
2324a49301eSmrg      fprintf(f,"# ppm-file created by osdemo.c\n");
2334a49301eSmrg      fprintf(f,"%i %i\n", width,height);
2344a49301eSmrg      fprintf(f,"255\n");
2354a49301eSmrg      fclose(f);
2364a49301eSmrg      f = fopen( filename, "ab" );  /* reopen in binary append mode */
23701e04c3fSmrg      if (!f) {
23801e04c3fSmrg         fprintf(stderr, "Error while reopening %s in write_ppm()\n",
23901e04c3fSmrg                 filename);
24001e04c3fSmrg         return;
24101e04c3fSmrg      }
2424a49301eSmrg      for (y=0; y < height; y++) {
2434a49301eSmrg         for (x = 0; x < width; x++) {
2444a49301eSmrg            int yy = invert ? (height - 1 - y) : y;
2454a49301eSmrg            int i = (yy * width + x) * comps;
2464a49301eSmrg            fputc(ptr[i+rcomp], f); /* write red */
2474a49301eSmrg            fputc(ptr[i+gcomp], f); /* write green */
2484a49301eSmrg            fputc(ptr[i+bcomp], f); /* write blue */
2494a49301eSmrg         }
2504a49301eSmrg      }
2514a49301eSmrg      fclose(f);
2524a49301eSmrg   }
2533464ebd5Sriastradh   else {
2543464ebd5Sriastradh      fprintf(stderr, "Unable to create %s in write_ppm()\n", filename);
2553464ebd5Sriastradh   }
2564a49301eSmrg}
2574a49301eSmrg
2584a49301eSmrg
2594a49301eSmrg/**
2604a49301eSmrg * Write a texture image to a ppm file.
2614a49301eSmrg * \param face  cube face in [0,5]
2624a49301eSmrg * \param level  mipmap level
2634a49301eSmrg */
2644a49301eSmrgstatic void
2654a49301eSmrgwrite_texture_image(struct gl_texture_object *texObj,
2664a49301eSmrg                    GLuint face, GLuint level)
2674a49301eSmrg{
2684a49301eSmrg   struct gl_texture_image *img = texObj->Image[face][level];
2694a49301eSmrg   if (img) {
2704a49301eSmrg      GET_CURRENT_CONTEXT(ctx);
2714a49301eSmrg      struct gl_pixelstore_attrib store;
2724a49301eSmrg      GLubyte *buffer;
2734a49301eSmrg      char s[100];
2744a49301eSmrg
275af69d88dSmrg      buffer = malloc(img->Width * img->Height
2764a49301eSmrg                                        * img->Depth * 4);
2774a49301eSmrg
2784a49301eSmrg      store = ctx->Pack; /* save */
2794a49301eSmrg      ctx->Pack = ctx->DefaultPacking;
2804a49301eSmrg
28101e04c3fSmrg      ctx->Driver.GetTexSubImage(ctx,
28201e04c3fSmrg                                 0, 0, 0, img->Width, img->Height, img->Depth,
28301e04c3fSmrg                                 GL_RGBA, GL_UNSIGNED_BYTE, buffer, img);
2844a49301eSmrg
2854a49301eSmrg      /* make filename */
2867ec681f3Smrg      snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
2874a49301eSmrg
288cdc920a0Smrg      printf("  Writing image level %u to %s\n", level, s);
2894a49301eSmrg      write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
2904a49301eSmrg
2914a49301eSmrg      ctx->Pack = store; /* restore */
2924a49301eSmrg
293cdc920a0Smrg      free(buffer);
2944a49301eSmrg   }
2954a49301eSmrg}
2964a49301eSmrg
2974a49301eSmrg
2984a49301eSmrg/**
2994a49301eSmrg * Write renderbuffer image to a ppm file.
3004a49301eSmrg */
3013464ebd5Sriastradhvoid
3023464ebd5Sriastradh_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb)
3034a49301eSmrg{
3044a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
3054a49301eSmrg   GLubyte *buffer;
3064a49301eSmrg   char s[100];
3074a49301eSmrg   GLenum format, type;
3084a49301eSmrg
3097ec681f3Smrg   if (rb->_BaseFormat == GL_RGB ||
3104a49301eSmrg       rb->_BaseFormat == GL_RGBA) {
3114a49301eSmrg      format = GL_RGBA;
3124a49301eSmrg      type = GL_UNSIGNED_BYTE;
3134a49301eSmrg   }
3144a49301eSmrg   else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
3154a49301eSmrg      format = GL_DEPTH_STENCIL;
3164a49301eSmrg      type = GL_UNSIGNED_INT_24_8;
3174a49301eSmrg   }
3184a49301eSmrg   else {
3193464ebd5Sriastradh      _mesa_debug(NULL,
3203464ebd5Sriastradh                  "Unsupported BaseFormat 0x%x in "
3213464ebd5Sriastradh                  "_mesa_write_renderbuffer_image()\n",
3223464ebd5Sriastradh                  rb->_BaseFormat);
3234a49301eSmrg      return;
3244a49301eSmrg   }
3254a49301eSmrg
326af69d88dSmrg   buffer = malloc(rb->Width * rb->Height * 4);
3274a49301eSmrg
3284a49301eSmrg   ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
3294a49301eSmrg                          format, type, &ctx->DefaultPacking, buffer);
3304a49301eSmrg
3314a49301eSmrg   /* make filename */
3327ec681f3Smrg   snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
3337ec681f3Smrg   snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name);
3344a49301eSmrg
335cdc920a0Smrg   printf("  Writing renderbuffer image to %s\n", s);
3363464ebd5Sriastradh
3373464ebd5Sriastradh   _mesa_debug(NULL, "  Writing renderbuffer image to %s\n", s);
3383464ebd5Sriastradh
3394a49301eSmrg   write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
3404a49301eSmrg
341cdc920a0Smrg   free(buffer);
3424a49301eSmrg}
3434a49301eSmrg
3444a49301eSmrg
3454a49301eSmrg/** How many texture images (mipmap levels, faces) to write to files */
3464a49301eSmrg#define WRITE_NONE 0
3474a49301eSmrg#define WRITE_ONE  1
3484a49301eSmrg#define WRITE_ALL  2
3494a49301eSmrg
3504a49301eSmrgstatic GLuint WriteImages;
3514a49301eSmrg
3524a49301eSmrg
3534a49301eSmrgstatic void
3544a49301eSmrgdump_texture(struct gl_texture_object *texObj, GLuint writeImages)
3554a49301eSmrg{
3564a49301eSmrg   const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
3574a49301eSmrg   GLboolean written = GL_FALSE;
3584a49301eSmrg   GLuint i, j;
3594a49301eSmrg
360cdc920a0Smrg   printf("Texture %u\n", texObj->Name);
361cdc920a0Smrg   printf("  Target %s\n", tex_target_name(texObj->Target));
3624a49301eSmrg   for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
3634a49301eSmrg      for (j = 0; j < numFaces; j++) {
3644a49301eSmrg         struct gl_texture_image *texImg = texObj->Image[j][i];
3654a49301eSmrg         if (texImg) {
366af69d88dSmrg            printf("  Face %u level %u: %d x %d x %d, format %s\n",
367cdc920a0Smrg		   j, i,
368cdc920a0Smrg		   texImg->Width, texImg->Height, texImg->Depth,
369af69d88dSmrg		   _mesa_get_format_name(texImg->TexFormat));
3704a49301eSmrg            if (writeImages == WRITE_ALL ||
3714a49301eSmrg                (writeImages == WRITE_ONE && !written)) {
3724a49301eSmrg               write_texture_image(texObj, j, i);
3734a49301eSmrg               written = GL_TRUE;
3744a49301eSmrg            }
3754a49301eSmrg         }
3764a49301eSmrg      }
3774a49301eSmrg   }
3784a49301eSmrg}
3794a49301eSmrg
3804a49301eSmrg
3814a49301eSmrg/**
3824a49301eSmrg * Dump a single texture.
3834a49301eSmrg */
3844a49301eSmrgvoid
3854a49301eSmrg_mesa_dump_texture(GLuint texture, GLuint writeImages)
3864a49301eSmrg{
3874a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
3884a49301eSmrg   struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
3894a49301eSmrg   if (texObj) {
3904a49301eSmrg      dump_texture(texObj, writeImages);
3914a49301eSmrg   }
3924a49301eSmrg}
3934a49301eSmrg
3944a49301eSmrg
3954a49301eSmrgstatic void
3967ec681f3Smrgdump_texture_cb(void *data, UNUSED void *userData)
3974a49301eSmrg{
3984a49301eSmrg   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
3994a49301eSmrg   dump_texture(texObj, WriteImages);
4004a49301eSmrg}
4014a49301eSmrg
4024a49301eSmrg
4034a49301eSmrg/**
4044a49301eSmrg * Print basic info about all texture objext to stdout.
4054a49301eSmrg * If dumpImages is true, write PPM of level[0] image to a file.
4064a49301eSmrg */
4074a49301eSmrgvoid
4084a49301eSmrg_mesa_dump_textures(GLuint writeImages)
4094a49301eSmrg{
4104a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4114a49301eSmrg   WriteImages = writeImages;
4124a49301eSmrg   _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
4134a49301eSmrg}
4144a49301eSmrg
4154a49301eSmrg
4164a49301eSmrgstatic void
4174a49301eSmrgdump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
4184a49301eSmrg{
419cdc920a0Smrg   printf("Renderbuffer %u: %u x %u  IntFormat = %s\n",
420cdc920a0Smrg	  rb->Name, rb->Width, rb->Height,
42101e04c3fSmrg	  _mesa_enum_to_string(rb->InternalFormat));
4224a49301eSmrg   if (writeImage) {
4233464ebd5Sriastradh      _mesa_write_renderbuffer_image(rb);
4244a49301eSmrg   }
4254a49301eSmrg}
4264a49301eSmrg
4274a49301eSmrg
4284a49301eSmrgstatic void
4297ec681f3Smrgdump_renderbuffer_cb(void *data, UNUSED void *userData)
4304a49301eSmrg{
4314a49301eSmrg   const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
4324a49301eSmrg   dump_renderbuffer(rb, WriteImages);
4334a49301eSmrg}
4344a49301eSmrg
4354a49301eSmrg
4364a49301eSmrg/**
4374a49301eSmrg * Print basic info about all renderbuffers to stdout.
4384a49301eSmrg * If dumpImages is true, write PPM of level[0] image to a file.
4394a49301eSmrg */
4404a49301eSmrgvoid
4414a49301eSmrg_mesa_dump_renderbuffers(GLboolean writeImages)
4424a49301eSmrg{
4434a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4444a49301eSmrg   WriteImages = writeImages;
4454a49301eSmrg   _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
4464a49301eSmrg}
4474a49301eSmrg
4484a49301eSmrg
4494a49301eSmrg
4504a49301eSmrgvoid
4514a49301eSmrg_mesa_dump_color_buffer(const char *filename)
4524a49301eSmrg{
4534a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4544a49301eSmrg   const GLuint w = ctx->DrawBuffer->Width;
4554a49301eSmrg   const GLuint h = ctx->DrawBuffer->Height;
4564a49301eSmrg   GLubyte *buf;
4574a49301eSmrg
458af69d88dSmrg   buf = malloc(w * h * 4);
4594a49301eSmrg
4604a49301eSmrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
4614a49301eSmrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
4624a49301eSmrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
4634a49301eSmrg
4644a49301eSmrg   _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
4654a49301eSmrg
466cdc920a0Smrg   printf("ReadBuffer %p 0x%x  DrawBuffer %p 0x%x\n",
467cdc920a0Smrg	  (void *) ctx->ReadBuffer->_ColorReadBuffer,
468cdc920a0Smrg	  ctx->ReadBuffer->ColorReadBuffer,
469cdc920a0Smrg	  (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
470cdc920a0Smrg	  ctx->DrawBuffer->ColorDrawBuffer[0]);
471cdc920a0Smrg   printf("Writing %d x %d color buffer to %s\n", w, h, filename);
4724a49301eSmrg   write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
4734a49301eSmrg
4744a49301eSmrg   _mesa_PopClientAttrib();
4754a49301eSmrg
476cdc920a0Smrg   free(buf);
4774a49301eSmrg}
4784a49301eSmrg
4794a49301eSmrg
4804a49301eSmrgvoid
4814a49301eSmrg_mesa_dump_depth_buffer(const char *filename)
4824a49301eSmrg{
4834a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
4844a49301eSmrg   const GLuint w = ctx->DrawBuffer->Width;
4854a49301eSmrg   const GLuint h = ctx->DrawBuffer->Height;
4864a49301eSmrg   GLuint *buf;
4874a49301eSmrg   GLubyte *buf2;
4884a49301eSmrg   GLuint i;
4894a49301eSmrg
490af69d88dSmrg   buf = malloc(w * h * 4);  /* 4 bpp */
491af69d88dSmrg   buf2 = malloc(w * h * 3); /* 3 bpp */
4924a49301eSmrg
4934a49301eSmrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
4944a49301eSmrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
4954a49301eSmrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
4964a49301eSmrg
4974a49301eSmrg   _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
4984a49301eSmrg
4994a49301eSmrg   /* spread 24 bits of Z across R, G, B */
5004a49301eSmrg   for (i = 0; i < w * h; i++) {
5014a49301eSmrg      buf2[i*3+0] = (buf[i] >> 24) & 0xff;
5024a49301eSmrg      buf2[i*3+1] = (buf[i] >> 16) & 0xff;
5034a49301eSmrg      buf2[i*3+2] = (buf[i] >>  8) & 0xff;
5044a49301eSmrg   }
5054a49301eSmrg
506cdc920a0Smrg   printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
5074a49301eSmrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
5084a49301eSmrg
5094a49301eSmrg   _mesa_PopClientAttrib();
5104a49301eSmrg
511cdc920a0Smrg   free(buf);
512cdc920a0Smrg   free(buf2);
5134a49301eSmrg}
5144a49301eSmrg
5154a49301eSmrg
5164a49301eSmrgvoid
5174a49301eSmrg_mesa_dump_stencil_buffer(const char *filename)
5184a49301eSmrg{
5194a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
5204a49301eSmrg   const GLuint w = ctx->DrawBuffer->Width;
5214a49301eSmrg   const GLuint h = ctx->DrawBuffer->Height;
5224a49301eSmrg   GLubyte *buf;
5234a49301eSmrg   GLubyte *buf2;
5244a49301eSmrg   GLuint i;
5254a49301eSmrg
526af69d88dSmrg   buf = malloc(w * h);  /* 1 bpp */
527af69d88dSmrg   buf2 = malloc(w * h * 3); /* 3 bpp */
5284a49301eSmrg
5294a49301eSmrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
5304a49301eSmrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
5314a49301eSmrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
5324a49301eSmrg
5334a49301eSmrg   _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
5344a49301eSmrg
5354a49301eSmrg   for (i = 0; i < w * h; i++) {
5364a49301eSmrg      buf2[i*3+0] = buf[i];
5374a49301eSmrg      buf2[i*3+1] = (buf[i] & 127) * 2;
5384a49301eSmrg      buf2[i*3+2] = (buf[i] - 128) * 2;
5394a49301eSmrg   }
5404a49301eSmrg
541cdc920a0Smrg   printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
5424a49301eSmrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
5434a49301eSmrg
5444a49301eSmrg   _mesa_PopClientAttrib();
5454a49301eSmrg
546cdc920a0Smrg   free(buf);
547cdc920a0Smrg   free(buf2);
5484a49301eSmrg}
5494a49301eSmrg
5504a49301eSmrg
5513464ebd5Sriastradhvoid
5523464ebd5Sriastradh_mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h,
5533464ebd5Sriastradh                 GLenum format, GLenum type)
5543464ebd5Sriastradh{
5553464ebd5Sriastradh   GLboolean invert = GL_TRUE;
5563464ebd5Sriastradh
5573464ebd5Sriastradh   if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
5583464ebd5Sriastradh      write_ppm(filename, image, w, h, 4, 0, 1, 2, invert);
5593464ebd5Sriastradh   }
5603464ebd5Sriastradh   else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) {
5613464ebd5Sriastradh      write_ppm(filename, image, w, h, 4, 2, 1, 0, invert);
5623464ebd5Sriastradh   }
5633464ebd5Sriastradh   else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) {
5643464ebd5Sriastradh      write_ppm(filename, image, w, h, 2, 1, 0, 0, invert);
5653464ebd5Sriastradh   }
566af69d88dSmrg   else if (format == GL_RED && type == GL_UNSIGNED_BYTE) {
567af69d88dSmrg      write_ppm(filename, image, w, h, 1, 0, 0, 0, invert);
568af69d88dSmrg   }
569af69d88dSmrg   else if (format == GL_RGBA && type == GL_FLOAT) {
570af69d88dSmrg      /* convert floats to ubyte */
571af69d88dSmrg      GLubyte *buf = malloc(w * h * 4 * sizeof(GLubyte));
572af69d88dSmrg      const GLfloat *f = (const GLfloat *) image;
573af69d88dSmrg      GLuint i;
574af69d88dSmrg      for (i = 0; i < w * h * 4; i++) {
575af69d88dSmrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
576af69d88dSmrg      }
577af69d88dSmrg      write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert);
578af69d88dSmrg      free(buf);
579af69d88dSmrg   }
580af69d88dSmrg   else if (format == GL_RED && type == GL_FLOAT) {
581af69d88dSmrg      /* convert floats to ubyte */
582af69d88dSmrg      GLubyte *buf = malloc(w * h * sizeof(GLubyte));
583af69d88dSmrg      const GLfloat *f = (const GLfloat *) image;
584af69d88dSmrg      GLuint i;
585af69d88dSmrg      for (i = 0; i < w * h; i++) {
586af69d88dSmrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
587af69d88dSmrg      }
588af69d88dSmrg      write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert);
589af69d88dSmrg      free(buf);
590af69d88dSmrg   }
5913464ebd5Sriastradh   else {
592af69d88dSmrg      _mesa_problem(NULL,
593af69d88dSmrg                 "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()",
594af69d88dSmrg                 format, type);
5953464ebd5Sriastradh   }
5963464ebd5Sriastradh}
5973464ebd5Sriastradh
5983464ebd5Sriastradh
5994a49301eSmrg/**
6004a49301eSmrg * Quick and dirty function to "print" a texture to stdout.
6014a49301eSmrg */
6024a49301eSmrgvoid
603af69d88dSmrg_mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img)
6044a49301eSmrg{
605af69d88dSmrg   const GLint slice = 0;
606af69d88dSmrg   GLint srcRowStride;
6074a49301eSmrg   GLuint i, j, c;
608af69d88dSmrg   GLubyte *data;
609af69d88dSmrg
610af69d88dSmrg   ctx->Driver.MapTextureImage(ctx, img, slice,
611af69d88dSmrg                               0, 0, img->Width, img->Height, GL_MAP_READ_BIT,
612af69d88dSmrg                               &data, &srcRowStride);
6134a49301eSmrg
6144a49301eSmrg   if (!data) {
615cdc920a0Smrg      printf("No texture data\n");
6164a49301eSmrg   }
617af69d88dSmrg   else {
618af69d88dSmrg      /* XXX add more formats or make into a new format utility function */
619af69d88dSmrg      switch (img->TexFormat) {
620af69d88dSmrg         case MESA_FORMAT_A_UNORM8:
621af69d88dSmrg         case MESA_FORMAT_L_UNORM8:
622af69d88dSmrg         case MESA_FORMAT_I_UNORM8:
623af69d88dSmrg            c = 1;
624af69d88dSmrg            break;
6257ec681f3Smrg         case MESA_FORMAT_LA_UNORM8:
626af69d88dSmrg            c = 2;
627af69d88dSmrg            break;
628af69d88dSmrg         case MESA_FORMAT_BGR_UNORM8:
629af69d88dSmrg         case MESA_FORMAT_RGB_UNORM8:
630af69d88dSmrg            c = 3;
631af69d88dSmrg            break;
632af69d88dSmrg         case MESA_FORMAT_A8B8G8R8_UNORM:
633af69d88dSmrg         case MESA_FORMAT_B8G8R8A8_UNORM:
634af69d88dSmrg            c = 4;
635af69d88dSmrg            break;
636af69d88dSmrg         default:
637af69d88dSmrg            _mesa_problem(NULL, "error in PrintTexture\n");
638af69d88dSmrg            return;
639af69d88dSmrg      }
6404a49301eSmrg
641af69d88dSmrg      for (i = 0; i < img->Height; i++) {
642af69d88dSmrg         for (j = 0; j < img->Width; j++) {
643af69d88dSmrg            if (c==1)
644af69d88dSmrg               printf("%02x  ", data[0]);
645af69d88dSmrg            else if (c==2)
646af69d88dSmrg               printf("%02x%02x  ", data[0], data[1]);
647af69d88dSmrg            else if (c==3)
648af69d88dSmrg               printf("%02x%02x%02x  ", data[0], data[1], data[2]);
649af69d88dSmrg            else if (c==4)
650af69d88dSmrg               printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
651af69d88dSmrg            data += (srcRowStride - img->Width) * c;
652af69d88dSmrg         }
653af69d88dSmrg         /* XXX use img->ImageStride here */
654af69d88dSmrg         printf("\n");
6554a49301eSmrg
6564a49301eSmrg      }
6574a49301eSmrg   }
658af69d88dSmrg
659af69d88dSmrg   ctx->Driver.UnmapTextureImage(ctx, img, slice);
6604a49301eSmrg}
661