Subversion Repositories Kolibri OS

Rev

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

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