Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  * Version:  6.5
  4.  *
  5.  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
  6.  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the "Software"),
  10.  * to deal in the Software without restriction, including without limitation
  11.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12.  * and/or sell copies of the Software, and to permit persons to whom the
  13.  * Software is furnished to do so, subject to the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice shall be included
  16.  * in all copies or substantial portions of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  21.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  22.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26. #include "mtypes.h"
  27. #include "attrib.h"
  28. #include "colormac.h"
  29. #include "enums.h"
  30. #include "formats.h"
  31. #include "hash.h"
  32. #include "imports.h"
  33. #include "debug.h"
  34. #include "get.h"
  35. #include "pixelstore.h"
  36. #include "readpix.h"
  37. #include "texobj.h"
  38.  
  39.  
  40. /**
  41.  * Primitive names
  42.  */
  43. const char *_mesa_prim_name[GL_POLYGON+4] = {
  44.    "GL_POINTS",
  45.    "GL_LINES",
  46.    "GL_LINE_LOOP",
  47.    "GL_LINE_STRIP",
  48.    "GL_TRIANGLES",
  49.    "GL_TRIANGLE_STRIP",
  50.    "GL_TRIANGLE_FAN",
  51.    "GL_QUADS",
  52.    "GL_QUAD_STRIP",
  53.    "GL_POLYGON",
  54.    "outside begin/end",
  55.    "inside unknown primitive",
  56.    "unknown state"
  57. };
  58.  
  59.  
  60. static const char *
  61. tex_target_name(GLenum tgt)
  62. {
  63.    static const struct {
  64.       GLenum target;
  65.       const char *name;
  66.    } tex_targets[] = {
  67.       { GL_TEXTURE_1D, "GL_TEXTURE_1D" },
  68.       { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
  69.       { GL_TEXTURE_3D, "GL_TEXTURE_3D" },
  70.       { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
  71.       { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" },
  72.       { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" },
  73.       { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" }
  74.    };
  75.    GLuint i;
  76.    for (i = 0; i < Elements(tex_targets); i++) {
  77.       if (tex_targets[i].target == tgt)
  78.          return tex_targets[i].name;
  79.    }
  80.    return "UNKNOWN TEX TARGET";
  81. }
  82.  
  83.  
  84. void
  85. _mesa_print_state( const char *msg, GLuint state )
  86. {
  87.    _mesa_debug(NULL,
  88.            "%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\n",
  89.            msg,
  90.            state,
  91.            (state & _NEW_MODELVIEW)       ? "ctx->ModelView, " : "",
  92.            (state & _NEW_PROJECTION)      ? "ctx->Projection, " : "",
  93.            (state & _NEW_TEXTURE_MATRIX)  ? "ctx->TextureMatrix, " : "",
  94.            (state & _NEW_ACCUM)           ? "ctx->Accum, " : "",
  95.            (state & _NEW_COLOR)           ? "ctx->Color, " : "",
  96.            (state & _NEW_DEPTH)           ? "ctx->Depth, " : "",
  97.            (state & _NEW_EVAL)            ? "ctx->Eval/EvalMap, " : "",
  98.            (state & _NEW_FOG)             ? "ctx->Fog, " : "",
  99.            (state & _NEW_HINT)            ? "ctx->Hint, " : "",
  100.            (state & _NEW_LIGHT)           ? "ctx->Light, " : "",
  101.            (state & _NEW_LINE)            ? "ctx->Line, " : "",
  102.            (state & _NEW_PIXEL)           ? "ctx->Pixel, " : "",
  103.            (state & _NEW_POINT)           ? "ctx->Point, " : "",
  104.            (state & _NEW_POLYGON)         ? "ctx->Polygon, " : "",
  105.            (state & _NEW_POLYGONSTIPPLE)  ? "ctx->PolygonStipple, " : "",
  106.            (state & _NEW_SCISSOR)         ? "ctx->Scissor, " : "",
  107.            (state & _NEW_STENCIL)         ? "ctx->Stencil, " : "",
  108.            (state & _NEW_TEXTURE)         ? "ctx->Texture, " : "",
  109.            (state & _NEW_TRANSFORM)       ? "ctx->Transform, " : "",
  110.            (state & _NEW_VIEWPORT)        ? "ctx->Viewport, " : "",
  111.            (state & _NEW_PACKUNPACK)      ? "ctx->Pack/Unpack, " : "",
  112.            (state & _NEW_ARRAY)           ? "ctx->Array, " : "",
  113.            (state & _NEW_RENDERMODE)      ? "ctx->RenderMode, " : "",
  114.            (state & _NEW_BUFFERS)         ? "ctx->Visual, ctx->DrawBuffer,, " : "");
  115. }
  116.  
  117.  
  118.  
  119. void
  120. _mesa_print_tri_caps( const char *name, GLuint flags )
  121. {
  122.    _mesa_debug(NULL,
  123.            "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
  124.            name,
  125.            flags,
  126.            (flags & DD_FLATSHADE)           ? "flat-shade, " : "",
  127.            (flags & DD_SEPARATE_SPECULAR)   ? "separate-specular, " : "",
  128.            (flags & DD_TRI_LIGHT_TWOSIDE)   ? "tri-light-twoside, " : "",
  129.            (flags & DD_TRI_TWOSTENCIL)      ? "tri-twostencil, " : "",
  130.            (flags & DD_TRI_UNFILLED)        ? "tri-unfilled, " : "",
  131.            (flags & DD_TRI_STIPPLE)         ? "tri-stipple, " : "",
  132.            (flags & DD_TRI_OFFSET)          ? "tri-offset, " : "",
  133.            (flags & DD_TRI_SMOOTH)          ? "tri-smooth, " : "",
  134.            (flags & DD_LINE_SMOOTH)         ? "line-smooth, " : "",
  135.            (flags & DD_LINE_STIPPLE)        ? "line-stipple, " : "",
  136.            (flags & DD_POINT_SMOOTH)        ? "point-smooth, " : "",
  137.            (flags & DD_POINT_ATTEN)         ? "point-atten, " : "",
  138.            (flags & DD_TRI_CULL_FRONT_BACK) ? "cull-all, " : ""
  139.       );
  140. }
  141.  
  142.  
  143. /**
  144.  * Print information about this Mesa version and build options.
  145.  */
  146. void _mesa_print_info( void )
  147. {
  148.    _mesa_debug(NULL, "Mesa GL_VERSION = %s\n",
  149.            (char *) _mesa_GetString(GL_VERSION));
  150.    _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n",
  151.            (char *) _mesa_GetString(GL_RENDERER));
  152.    _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n",
  153.            (char *) _mesa_GetString(GL_VENDOR));
  154.    _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n",
  155.            (char *) _mesa_GetString(GL_EXTENSIONS));
  156. #if defined(THREADS)
  157.    _mesa_debug(NULL, "Mesa thread-safe: YES\n");
  158. #else
  159.    _mesa_debug(NULL, "Mesa thread-safe: NO\n");
  160. #endif
  161. #if defined(USE_X86_ASM)
  162.    _mesa_debug(NULL, "Mesa x86-optimized: YES\n");
  163. #else
  164.    _mesa_debug(NULL, "Mesa x86-optimized: NO\n");
  165. #endif
  166. #if defined(USE_SPARC_ASM)
  167.    _mesa_debug(NULL, "Mesa sparc-optimized: YES\n");
  168. #else
  169.    _mesa_debug(NULL, "Mesa sparc-optimized: NO\n");
  170. #endif
  171. }
  172.  
  173.  
  174. /**
  175.  * Set the debugging flags.
  176.  *
  177.  * \param debug debug string
  178.  *
  179.  * If compiled with debugging support then search for keywords in \p debug and
  180.  * enables the verbose debug output of the respective feature.
  181.  */
  182. static void add_debug_flags( const char *debug )
  183. {
  184. #ifdef DEBUG
  185.    struct debug_option {
  186.       const char *name;
  187.       GLbitfield flag;
  188.    };
  189.    static const struct debug_option debug_opt[] = {
  190.       { "varray",    VERBOSE_VARRAY },
  191.       { "tex",       VERBOSE_TEXTURE },
  192.       { "mat",       VERBOSE_MATERIAL },
  193.       { "pipe",      VERBOSE_PIPELINE },
  194.       { "driver",    VERBOSE_DRIVER },
  195.       { "state",     VERBOSE_STATE },
  196.       { "api",       VERBOSE_API },
  197.       { "list",      VERBOSE_DISPLAY_LIST },
  198.       { "lighting",  VERBOSE_LIGHTING },
  199.       { "disassem",  VERBOSE_DISASSEM },
  200.       { "draw",      VERBOSE_DRAW },
  201.       { "swap",      VERBOSE_SWAPBUFFERS }
  202.    };
  203.    GLuint i;
  204.  
  205.    MESA_VERBOSE = 0x0;
  206.    for (i = 0; i < Elements(debug_opt); i++) {
  207.       if (strstr(debug, debug_opt[i].name))
  208.          MESA_VERBOSE |= debug_opt[i].flag;
  209.    }
  210.  
  211.    /* Debug flag:
  212.     */
  213.    if (strstr(debug, "flush"))
  214.       MESA_DEBUG_FLAGS |= DEBUG_ALWAYS_FLUSH;
  215.  
  216. #if defined(_FPU_GETCW) && defined(_FPU_SETCW)
  217.    if (strstr(debug, "fpexceptions")) {
  218.       /* raise FP exceptions */
  219.       fpu_control_t mask;
  220.       _FPU_GETCW(mask);
  221.       mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
  222.                 | _FPU_MASK_OM | _FPU_MASK_UM);
  223.       _FPU_SETCW(mask);
  224.    }
  225. #endif
  226.  
  227. #else
  228.    (void) debug;
  229. #endif
  230. }
  231.  
  232.  
  233. void
  234. _mesa_init_debug( struct gl_context *ctx )
  235. {
  236.    char *c;
  237.  
  238.    /* Dither disable */
  239.    ctx->NoDither = _mesa_getenv("MESA_NO_DITHER") ? GL_TRUE : GL_FALSE;
  240.    if (ctx->NoDither) {
  241.       if (_mesa_getenv("MESA_DEBUG")) {
  242.          _mesa_debug(ctx, "MESA_NO_DITHER set - dithering disabled\n");
  243.       }
  244.       ctx->Color.DitherFlag = GL_FALSE;
  245.    }
  246.  
  247.    c = _mesa_getenv("MESA_DEBUG");
  248.    if (c)
  249.       add_debug_flags(c);
  250.  
  251.    c = _mesa_getenv("MESA_VERBOSE");
  252.    if (c)
  253.       add_debug_flags(c);
  254. }
  255.  
  256.  
  257. /*
  258.  * Write ppm file
  259.  */
  260. static void
  261. write_ppm(const char *filename, const GLubyte *buffer, int width, int height,
  262.           int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
  263. {
  264.    FILE *f = fopen( filename, "w" );
  265.    if (f) {
  266.       int x, y;
  267.       const GLubyte *ptr = buffer;
  268.       fprintf(f,"P6\n");
  269.       fprintf(f,"# ppm-file created by osdemo.c\n");
  270.       fprintf(f,"%i %i\n", width,height);
  271.       fprintf(f,"255\n");
  272.       fclose(f);
  273.       f = fopen( filename, "ab" );  /* reopen in binary append mode */
  274.       for (y=0; y < height; y++) {
  275.          for (x = 0; x < width; x++) {
  276.             int yy = invert ? (height - 1 - y) : y;
  277.             int i = (yy * width + x) * comps;
  278.             fputc(ptr[i+rcomp], f); /* write red */
  279.             fputc(ptr[i+gcomp], f); /* write green */
  280.             fputc(ptr[i+bcomp], f); /* write blue */
  281.          }
  282.       }
  283.       fclose(f);
  284.    }
  285. }
  286.  
  287.  
  288. /**
  289.  * Write a texture image to a ppm file.
  290.  * \param face  cube face in [0,5]
  291.  * \param level  mipmap level
  292.  */
  293. static void
  294. write_texture_image(struct gl_texture_object *texObj,
  295.                     GLuint face, GLuint level)
  296. {
  297.    struct gl_texture_image *img = texObj->Image[face][level];
  298.    if (img) {
  299.       GET_CURRENT_CONTEXT(ctx);
  300.       struct gl_pixelstore_attrib store;
  301.       GLubyte *buffer;
  302.       char s[100];
  303.  
  304.       buffer = (GLubyte *) malloc(img->Width * img->Height
  305.                                         * img->Depth * 4);
  306.  
  307.       store = ctx->Pack; /* save */
  308.       ctx->Pack = ctx->DefaultPacking;
  309.  
  310.       ctx->Driver.GetTexImage(ctx, texObj->Target, level,
  311.                               GL_RGBA, GL_UNSIGNED_BYTE,
  312.                               buffer, texObj, img);
  313.  
  314.       /* make filename */
  315.       _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
  316.  
  317.       printf("  Writing image level %u to %s\n", level, s);
  318.       write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
  319.  
  320.       ctx->Pack = store; /* restore */
  321.  
  322.       free(buffer);
  323.    }
  324. }
  325.  
  326.  
  327. /**
  328.  * Write renderbuffer image to a ppm file.
  329.  */
  330. static void
  331. write_renderbuffer_image(const struct gl_renderbuffer *rb)
  332. {
  333.    GET_CURRENT_CONTEXT(ctx);
  334.    GLubyte *buffer;
  335.    char s[100];
  336.    GLenum format, type;
  337.  
  338.    if (rb->_BaseFormat == GL_RGB ||
  339.        rb->_BaseFormat == GL_RGBA) {
  340.       format = GL_RGBA;
  341.       type = GL_UNSIGNED_BYTE;
  342.    }
  343.    else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
  344.       format = GL_DEPTH_STENCIL;
  345.       type = GL_UNSIGNED_INT_24_8;
  346.    }
  347.    else {
  348.       return;
  349.    }
  350.  
  351.    buffer = (GLubyte *) malloc(rb->Width * rb->Height * 4);
  352.  
  353.    ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
  354.                           format, type, &ctx->DefaultPacking, buffer);
  355.  
  356.    /* make filename */
  357.    _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
  358.  
  359.    printf("  Writing renderbuffer image to %s\n", s);
  360.    write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
  361.  
  362.    free(buffer);
  363. }
  364.  
  365.  
  366. /** How many texture images (mipmap levels, faces) to write to files */
  367. #define WRITE_NONE 0
  368. #define WRITE_ONE  1
  369. #define WRITE_ALL  2
  370.  
  371. static GLuint WriteImages;
  372.  
  373.  
  374. static void
  375. dump_texture(struct gl_texture_object *texObj, GLuint writeImages)
  376. {
  377.    const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
  378.    GLboolean written = GL_FALSE;
  379.    GLuint i, j;
  380.  
  381.    printf("Texture %u\n", texObj->Name);
  382.    printf("  Target %s\n", tex_target_name(texObj->Target));
  383.    for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
  384.       for (j = 0; j < numFaces; j++) {
  385.          struct gl_texture_image *texImg = texObj->Image[j][i];
  386.          if (texImg) {
  387.             printf("  Face %u level %u: %d x %d x %d, format %s at %p\n",
  388.                    j, i,
  389.                    texImg->Width, texImg->Height, texImg->Depth,
  390.                    _mesa_get_format_name(texImg->TexFormat),
  391.                    texImg->Data);
  392.             if (writeImages == WRITE_ALL ||
  393.                 (writeImages == WRITE_ONE && !written)) {
  394.                write_texture_image(texObj, j, i);
  395.                written = GL_TRUE;
  396.             }
  397.          }
  398.       }
  399.    }
  400. }
  401.  
  402.  
  403. /**
  404.  * Dump a single texture.
  405.  */
  406. void
  407. _mesa_dump_texture(GLuint texture, GLuint writeImages)
  408. {
  409.    GET_CURRENT_CONTEXT(ctx);
  410.    struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
  411.    if (texObj) {
  412.       dump_texture(texObj, writeImages);
  413.    }
  414. }
  415.  
  416.  
  417. static void
  418. dump_texture_cb(GLuint id, void *data, void *userData)
  419. {
  420.    struct gl_texture_object *texObj = (struct gl_texture_object *) data;
  421.    (void) userData;
  422.    dump_texture(texObj, WriteImages);
  423. }
  424.  
  425.  
  426. /**
  427.  * Print basic info about all texture objext to stdout.
  428.  * If dumpImages is true, write PPM of level[0] image to a file.
  429.  */
  430. void
  431. _mesa_dump_textures(GLuint writeImages)
  432. {
  433.    GET_CURRENT_CONTEXT(ctx);
  434.    WriteImages = writeImages;
  435.    _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
  436. }
  437.  
  438.  
  439. static void
  440. dump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
  441. {
  442.    printf("Renderbuffer %u: %u x %u  IntFormat = %s\n",
  443.           rb->Name, rb->Width, rb->Height,
  444.           _mesa_lookup_enum_by_nr(rb->InternalFormat));
  445.    if (writeImage) {
  446.       write_renderbuffer_image(rb);
  447.    }
  448. }
  449.  
  450.  
  451. static void
  452. dump_renderbuffer_cb(GLuint id, void *data, void *userData)
  453. {
  454.    const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
  455.    (void) userData;
  456.    dump_renderbuffer(rb, WriteImages);
  457. }
  458.  
  459.  
  460. /**
  461.  * Print basic info about all renderbuffers to stdout.
  462.  * If dumpImages is true, write PPM of level[0] image to a file.
  463.  */
  464. void
  465. _mesa_dump_renderbuffers(GLboolean writeImages)
  466. {
  467.    GET_CURRENT_CONTEXT(ctx);
  468.    WriteImages = writeImages;
  469.    _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
  470. }
  471.  
  472.  
  473.  
  474. void
  475. _mesa_dump_color_buffer(const char *filename)
  476. {
  477.    GET_CURRENT_CONTEXT(ctx);
  478.    const GLuint w = ctx->DrawBuffer->Width;
  479.    const GLuint h = ctx->DrawBuffer->Height;
  480.    GLubyte *buf;
  481.  
  482.    buf = (GLubyte *) malloc(w * h * 4);
  483.  
  484.    _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
  485.    _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
  486.    _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  487.  
  488.    _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  489.  
  490.    printf("ReadBuffer %p 0x%x  DrawBuffer %p 0x%x\n",
  491.           (void *) ctx->ReadBuffer->_ColorReadBuffer,
  492.           ctx->ReadBuffer->ColorReadBuffer,
  493.           (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
  494.           ctx->DrawBuffer->ColorDrawBuffer[0]);
  495.    printf("Writing %d x %d color buffer to %s\n", w, h, filename);
  496.    write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
  497.  
  498.    _mesa_PopClientAttrib();
  499.  
  500.    free(buf);
  501. }
  502.  
  503.  
  504. void
  505. _mesa_dump_depth_buffer(const char *filename)
  506. {
  507.    GET_CURRENT_CONTEXT(ctx);
  508.    const GLuint w = ctx->DrawBuffer->Width;
  509.    const GLuint h = ctx->DrawBuffer->Height;
  510.    GLuint *buf;
  511.    GLubyte *buf2;
  512.    GLuint i;
  513.  
  514.    buf = (GLuint *) malloc(w * h * 4);  /* 4 bpp */
  515.    buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */
  516.  
  517.    _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
  518.    _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
  519.    _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  520.  
  521.    _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
  522.  
  523.    /* spread 24 bits of Z across R, G, B */
  524.    for (i = 0; i < w * h; i++) {
  525.       buf2[i*3+0] = (buf[i] >> 24) & 0xff;
  526.       buf2[i*3+1] = (buf[i] >> 16) & 0xff;
  527.       buf2[i*3+2] = (buf[i] >>  8) & 0xff;
  528.    }
  529.  
  530.    printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
  531.    write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
  532.  
  533.    _mesa_PopClientAttrib();
  534.  
  535.    free(buf);
  536.    free(buf2);
  537. }
  538.  
  539.  
  540. void
  541. _mesa_dump_stencil_buffer(const char *filename)
  542. {
  543.    GET_CURRENT_CONTEXT(ctx);
  544.    const GLuint w = ctx->DrawBuffer->Width;
  545.    const GLuint h = ctx->DrawBuffer->Height;
  546.    GLubyte *buf;
  547.    GLubyte *buf2;
  548.    GLuint i;
  549.  
  550.    buf = (GLubyte *) malloc(w * h);  /* 1 bpp */
  551.    buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */
  552.  
  553.    _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
  554.    _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
  555.    _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  556.  
  557.    _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
  558.  
  559.    for (i = 0; i < w * h; i++) {
  560.       buf2[i*3+0] = buf[i];
  561.       buf2[i*3+1] = (buf[i] & 127) * 2;
  562.       buf2[i*3+2] = (buf[i] - 128) * 2;
  563.    }
  564.  
  565.    printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
  566.    write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
  567.  
  568.    _mesa_PopClientAttrib();
  569.  
  570.    free(buf);
  571.    free(buf2);
  572. }
  573.  
  574.  
  575. /**
  576.  * Quick and dirty function to "print" a texture to stdout.
  577.  */
  578. void
  579. _mesa_print_texture(struct gl_context *ctx, const struct gl_texture_image *img)
  580. {
  581. #if CHAN_TYPE != GL_UNSIGNED_BYTE
  582.    _mesa_problem(NULL, "PrintTexture not supported");
  583. #else
  584.    GLuint i, j, c;
  585.    const GLubyte *data = (const GLubyte *) img->Data;
  586.  
  587.    if (!data) {
  588.       printf("No texture data\n");
  589.       return;
  590.    }
  591.  
  592.    /* XXX add more formats or make into a new format utility function */
  593.    switch (img->TexFormat) {
  594.       case MESA_FORMAT_A8:
  595.       case MESA_FORMAT_L8:
  596.       case MESA_FORMAT_I8:
  597.       case MESA_FORMAT_CI8:
  598.          c = 1;
  599.          break;
  600.       case MESA_FORMAT_AL88:
  601.       case MESA_FORMAT_AL88_REV:
  602.          c = 2;
  603.          break;
  604.       case MESA_FORMAT_RGB888:
  605.       case MESA_FORMAT_BGR888:
  606.          c = 3;
  607.          break;
  608.       case MESA_FORMAT_RGBA8888:
  609.       case MESA_FORMAT_ARGB8888:
  610.          c = 4;
  611.          break;
  612.       default:
  613.          _mesa_problem(NULL, "error in PrintTexture\n");
  614.          return;
  615.    }
  616.  
  617.    for (i = 0; i < img->Height; i++) {
  618.       for (j = 0; j < img->Width; j++) {
  619.          if (c==1)
  620.             printf("%02x  ", data[0]);
  621.          else if (c==2)
  622.             printf("%02x%02x  ", data[0], data[1]);
  623.          else if (c==3)
  624.             printf("%02x%02x%02x  ", data[0], data[1], data[2]);
  625.          else if (c==4)
  626.             printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
  627.          data += (img->RowStride - img->Width) * c;
  628.       }
  629.       /* XXX use img->ImageStride here */
  630.       printf("\n");
  631.    }
  632. #endif
  633. }
  634.