Subversion Repositories Kolibri OS

Rev

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.    struct option {
  144.       const char *name;
  145.       GLbitfield flag;
  146.    };
  147.    static const struct option opts[] = {
  148.       { "varray",    VERBOSE_VARRAY },
  149.       { "tex",       VERBOSE_TEXTURE },
  150.       { "mat",       VERBOSE_MATERIAL },
  151.       { "pipe",      VERBOSE_PIPELINE },
  152.       { "driver",    VERBOSE_DRIVER },
  153.       { "state",     VERBOSE_STATE },
  154.       { "api",       VERBOSE_API },
  155.       { "list",      VERBOSE_DISPLAY_LIST },
  156.       { "lighting",  VERBOSE_LIGHTING },
  157.       { "disassem",  VERBOSE_DISASSEM },
  158.       { "draw",      VERBOSE_DRAW },
  159.       { "swap",      VERBOSE_SWAPBUFFERS }
  160.    };
  161.    GLuint i;
  162.  
  163.    if (!str)
  164.       return;
  165.  
  166.    MESA_VERBOSE = 0x0;
  167.    for (i = 0; i < Elements(opts); i++) {
  168.       if (strstr(str, opts[i].name) || strcmp(str, "all") == 0)
  169.          MESA_VERBOSE |= opts[i].flag;
  170.    }
  171. #endif
  172. }
  173.  
  174.  
  175. /**
  176.  * Set debugging flags.  When these flags are set, Mesa will do additional
  177.  * debug checks or actions.
  178.  * \param str  a comma-separated list of keywords
  179.  */
  180. static void
  181. set_debug_flags(const char *str)
  182. {
  183. #ifdef DEBUG
  184.    struct option {
  185.       const char *name;
  186.       GLbitfield flag;
  187.    };
  188.    static const struct option opts[] = {
  189.       { "silent", DEBUG_SILENT }, /* turn off debug messages */
  190.       { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */
  191.       { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE },
  192.       { "incomplete_fbo", DEBUG_INCOMPLETE_FBO }
  193.    };
  194.    GLuint i;
  195.  
  196.    if (!str)
  197.       return;
  198.  
  199.    MESA_DEBUG_FLAGS = 0x0;
  200.    for (i = 0; i < Elements(opts); i++) {
  201.       if (strstr(str, opts[i].name))
  202.          MESA_DEBUG_FLAGS |= opts[i].flag;
  203.    }
  204. #endif
  205. }
  206.  
  207.  
  208. /**
  209.  * Initialize debugging variables from env vars.
  210.  */
  211. void
  212. _mesa_init_debug( struct gl_context *ctx )
  213. {
  214.    set_debug_flags(_mesa_getenv("MESA_DEBUG"));
  215.    set_verbose_flags(_mesa_getenv("MESA_VERBOSE"));
  216. }
  217.  
  218.  
  219. /*
  220.  * Write ppm file
  221.  */
  222. static void
  223. write_ppm(const char *filename, const GLubyte *buffer, int width, int height,
  224.           int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
  225. {
  226.    FILE *f = fopen( filename, "w" );
  227.    if (f) {
  228.       int x, y;
  229.       const GLubyte *ptr = buffer;
  230.       fprintf(f,"P6\n");
  231.       fprintf(f,"# ppm-file created by osdemo.c\n");
  232.       fprintf(f,"%i %i\n", width,height);
  233.       fprintf(f,"255\n");
  234.       fclose(f);
  235.       f = fopen( filename, "ab" );  /* reopen in binary append mode */
  236.       for (y=0; y < height; y++) {
  237.          for (x = 0; x < width; x++) {
  238.             int yy = invert ? (height - 1 - y) : y;
  239.             int i = (yy * width + x) * comps;
  240.             fputc(ptr[i+rcomp], f); /* write red */
  241.             fputc(ptr[i+gcomp], f); /* write green */
  242.             fputc(ptr[i+bcomp], f); /* write blue */
  243.          }
  244.       }
  245.       fclose(f);
  246.    }
  247.    else {
  248.       fprintf(stderr, "Unable to create %s in write_ppm()\n", filename);
  249.    }
  250. }
  251.  
  252.  
  253. /**
  254.  * Write a texture image to a ppm file.
  255.  * \param face  cube face in [0,5]
  256.  * \param level  mipmap level
  257.  */
  258. static void
  259. write_texture_image(struct gl_texture_object *texObj,
  260.                     GLuint face, GLuint level)
  261. {
  262.    struct gl_texture_image *img = texObj->Image[face][level];
  263.    if (img) {
  264.       GET_CURRENT_CONTEXT(ctx);
  265.       struct gl_pixelstore_attrib store;
  266.       GLubyte *buffer;
  267.       char s[100];
  268.  
  269.       buffer = malloc(img->Width * img->Height
  270.                                         * img->Depth * 4);
  271.  
  272.       store = ctx->Pack; /* save */
  273.       ctx->Pack = ctx->DefaultPacking;
  274.  
  275.       ctx->Driver.GetTexImage(ctx, GL_RGBA, GL_UNSIGNED_BYTE, buffer, img);
  276.  
  277.       /* make filename */
  278.       _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
  279.  
  280.       printf("  Writing image level %u to %s\n", level, s);
  281.       write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
  282.  
  283.       ctx->Pack = store; /* restore */
  284.  
  285.       free(buffer);
  286.    }
  287. }
  288.  
  289.  
  290. /**
  291.  * Write renderbuffer image to a ppm file.
  292.  */
  293. void
  294. _mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb)
  295. {
  296.    GET_CURRENT_CONTEXT(ctx);
  297.    GLubyte *buffer;
  298.    char s[100];
  299.    GLenum format, type;
  300.  
  301.    if (rb->_BaseFormat == GL_RGB ||
  302.        rb->_BaseFormat == GL_RGBA) {
  303.       format = GL_RGBA;
  304.       type = GL_UNSIGNED_BYTE;
  305.    }
  306.    else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
  307.       format = GL_DEPTH_STENCIL;
  308.       type = GL_UNSIGNED_INT_24_8;
  309.    }
  310.    else {
  311.       _mesa_debug(NULL,
  312.                   "Unsupported BaseFormat 0x%x in "
  313.                   "_mesa_write_renderbuffer_image()\n",
  314.                   rb->_BaseFormat);
  315.       return;
  316.    }
  317.  
  318.    buffer = malloc(rb->Width * rb->Height * 4);
  319.  
  320.    ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
  321.                           format, type, &ctx->DefaultPacking, buffer);
  322.  
  323.    /* make filename */
  324.    _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
  325.    _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name);
  326.  
  327.    printf("  Writing renderbuffer image to %s\n", s);
  328.  
  329.    _mesa_debug(NULL, "  Writing renderbuffer image to %s\n", s);
  330.  
  331.    write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
  332.  
  333.    free(buffer);
  334. }
  335.  
  336.  
  337. /** How many texture images (mipmap levels, faces) to write to files */
  338. #define WRITE_NONE 0
  339. #define WRITE_ONE  1
  340. #define WRITE_ALL  2
  341.  
  342. static GLuint WriteImages;
  343.  
  344.  
  345. static void
  346. dump_texture(struct gl_texture_object *texObj, GLuint writeImages)
  347. {
  348.    const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
  349.    GLboolean written = GL_FALSE;
  350.    GLuint i, j;
  351.  
  352.    printf("Texture %u\n", texObj->Name);
  353.    printf("  Target %s\n", tex_target_name(texObj->Target));
  354.    for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
  355.       for (j = 0; j < numFaces; j++) {
  356.          struct gl_texture_image *texImg = texObj->Image[j][i];
  357.          if (texImg) {
  358.             printf("  Face %u level %u: %d x %d x %d, format %s\n",
  359.                    j, i,
  360.                    texImg->Width, texImg->Height, texImg->Depth,
  361.                    _mesa_get_format_name(texImg->TexFormat));
  362.             if (writeImages == WRITE_ALL ||
  363.                 (writeImages == WRITE_ONE && !written)) {
  364.                write_texture_image(texObj, j, i);
  365.                written = GL_TRUE;
  366.             }
  367.          }
  368.       }
  369.    }
  370. }
  371.  
  372.  
  373. /**
  374.  * Dump a single texture.
  375.  */
  376. void
  377. _mesa_dump_texture(GLuint texture, GLuint writeImages)
  378. {
  379.    GET_CURRENT_CONTEXT(ctx);
  380.    struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
  381.    if (texObj) {
  382.       dump_texture(texObj, writeImages);
  383.    }
  384. }
  385.  
  386.  
  387. static void
  388. dump_texture_cb(GLuint id, void *data, void *userData)
  389. {
  390.    struct gl_texture_object *texObj = (struct gl_texture_object *) data;
  391.    (void) userData;
  392.    dump_texture(texObj, WriteImages);
  393. }
  394.  
  395.  
  396. /**
  397.  * Print basic info about all texture objext to stdout.
  398.  * If dumpImages is true, write PPM of level[0] image to a file.
  399.  */
  400. void
  401. _mesa_dump_textures(GLuint writeImages)
  402. {
  403.    GET_CURRENT_CONTEXT(ctx);
  404.    WriteImages = writeImages;
  405.    _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
  406. }
  407.  
  408.  
  409. static void
  410. dump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
  411. {
  412.    printf("Renderbuffer %u: %u x %u  IntFormat = %s\n",
  413.           rb->Name, rb->Width, rb->Height,
  414.           _mesa_lookup_enum_by_nr(rb->InternalFormat));
  415.    if (writeImage) {
  416.       _mesa_write_renderbuffer_image(rb);
  417.    }
  418. }
  419.  
  420.  
  421. static void
  422. dump_renderbuffer_cb(GLuint id, void *data, void *userData)
  423. {
  424.    const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
  425.    (void) userData;
  426.    dump_renderbuffer(rb, WriteImages);
  427. }
  428.  
  429.  
  430. /**
  431.  * Print basic info about all renderbuffers to stdout.
  432.  * If dumpImages is true, write PPM of level[0] image to a file.
  433.  */
  434. void
  435. _mesa_dump_renderbuffers(GLboolean writeImages)
  436. {
  437.    GET_CURRENT_CONTEXT(ctx);
  438.    WriteImages = writeImages;
  439.    _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
  440. }
  441.  
  442.  
  443.  
  444. void
  445. _mesa_dump_color_buffer(const char *filename)
  446. {
  447.    GET_CURRENT_CONTEXT(ctx);
  448.    const GLuint w = ctx->DrawBuffer->Width;
  449.    const GLuint h = ctx->DrawBuffer->Height;
  450.    GLubyte *buf;
  451.  
  452.    buf = malloc(w * h * 4);
  453.  
  454.    _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
  455.    _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
  456.    _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  457.  
  458.    _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  459.  
  460.    printf("ReadBuffer %p 0x%x  DrawBuffer %p 0x%x\n",
  461.           (void *) ctx->ReadBuffer->_ColorReadBuffer,
  462.           ctx->ReadBuffer->ColorReadBuffer,
  463.           (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
  464.           ctx->DrawBuffer->ColorDrawBuffer[0]);
  465.    printf("Writing %d x %d color buffer to %s\n", w, h, filename);
  466.    write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
  467.  
  468.    _mesa_PopClientAttrib();
  469.  
  470.    free(buf);
  471. }
  472.  
  473.  
  474. void
  475. _mesa_dump_depth_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.    GLuint *buf;
  481.    GLubyte *buf2;
  482.    GLuint i;
  483.  
  484.    buf = malloc(w * h * 4);  /* 4 bpp */
  485.    buf2 = malloc(w * h * 3); /* 3 bpp */
  486.  
  487.    _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
  488.    _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
  489.    _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  490.  
  491.    _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
  492.  
  493.    /* spread 24 bits of Z across R, G, B */
  494.    for (i = 0; i < w * h; i++) {
  495.       buf2[i*3+0] = (buf[i] >> 24) & 0xff;
  496.       buf2[i*3+1] = (buf[i] >> 16) & 0xff;
  497.       buf2[i*3+2] = (buf[i] >>  8) & 0xff;
  498.    }
  499.  
  500.    printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
  501.    write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
  502.  
  503.    _mesa_PopClientAttrib();
  504.  
  505.    free(buf);
  506.    free(buf2);
  507. }
  508.  
  509.  
  510. void
  511. _mesa_dump_stencil_buffer(const char *filename)
  512. {
  513.    GET_CURRENT_CONTEXT(ctx);
  514.    const GLuint w = ctx->DrawBuffer->Width;
  515.    const GLuint h = ctx->DrawBuffer->Height;
  516.    GLubyte *buf;
  517.    GLubyte *buf2;
  518.    GLuint i;
  519.  
  520.    buf = malloc(w * h);  /* 1 bpp */
  521.    buf2 = malloc(w * h * 3); /* 3 bpp */
  522.  
  523.    _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
  524.    _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
  525.    _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
  526.  
  527.    _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
  528.  
  529.    for (i = 0; i < w * h; i++) {
  530.       buf2[i*3+0] = buf[i];
  531.       buf2[i*3+1] = (buf[i] & 127) * 2;
  532.       buf2[i*3+2] = (buf[i] - 128) * 2;
  533.    }
  534.  
  535.    printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
  536.    write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
  537.  
  538.    _mesa_PopClientAttrib();
  539.  
  540.    free(buf);
  541.    free(buf2);
  542. }
  543.  
  544.  
  545. void
  546. _mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h,
  547.                  GLenum format, GLenum type)
  548. {
  549.    GLboolean invert = GL_TRUE;
  550.  
  551.    if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
  552.       write_ppm(filename, image, w, h, 4, 0, 1, 2, invert);
  553.    }
  554.    else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) {
  555.       write_ppm(filename, image, w, h, 4, 2, 1, 0, invert);
  556.    }
  557.    else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) {
  558.       write_ppm(filename, image, w, h, 2, 1, 0, 0, invert);
  559.    }
  560.    else if (format == GL_RED && type == GL_UNSIGNED_BYTE) {
  561.       write_ppm(filename, image, w, h, 1, 0, 0, 0, invert);
  562.    }
  563.    else if (format == GL_RGBA && type == GL_FLOAT) {
  564.       /* convert floats to ubyte */
  565.       GLubyte *buf = malloc(w * h * 4 * sizeof(GLubyte));
  566.       const GLfloat *f = (const GLfloat *) image;
  567.       GLuint i;
  568.       for (i = 0; i < w * h * 4; i++) {
  569.          UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
  570.       }
  571.       write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert);
  572.       free(buf);
  573.    }
  574.    else if (format == GL_RED && type == GL_FLOAT) {
  575.       /* convert floats to ubyte */
  576.       GLubyte *buf = malloc(w * h * sizeof(GLubyte));
  577.       const GLfloat *f = (const GLfloat *) image;
  578.       GLuint i;
  579.       for (i = 0; i < w * h; i++) {
  580.          UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
  581.       }
  582.       write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert);
  583.       free(buf);
  584.    }
  585.    else {
  586.       _mesa_problem(NULL,
  587.                  "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()",
  588.                  format, type);
  589.    }
  590. }
  591.  
  592.  
  593. /**
  594.  * Quick and dirty function to "print" a texture to stdout.
  595.  */
  596. void
  597. _mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img)
  598. {
  599.    const GLint slice = 0;
  600.    GLint srcRowStride;
  601.    GLuint i, j, c;
  602.    GLubyte *data;
  603.  
  604.    ctx->Driver.MapTextureImage(ctx, img, slice,
  605.                                0, 0, img->Width, img->Height, GL_MAP_READ_BIT,
  606.                                &data, &srcRowStride);
  607.  
  608.    if (!data) {
  609.       printf("No texture data\n");
  610.    }
  611.    else {
  612.       /* XXX add more formats or make into a new format utility function */
  613.       switch (img->TexFormat) {
  614.          case MESA_FORMAT_A8:
  615.          case MESA_FORMAT_L8:
  616.          case MESA_FORMAT_I8:
  617.             c = 1;
  618.             break;
  619.          case MESA_FORMAT_AL88:
  620.          case MESA_FORMAT_AL88_REV:
  621.             c = 2;
  622.             break;
  623.          case MESA_FORMAT_RGB888:
  624.          case MESA_FORMAT_BGR888:
  625.             c = 3;
  626.             break;
  627.          case MESA_FORMAT_RGBA8888:
  628.          case MESA_FORMAT_ARGB8888:
  629.             c = 4;
  630.             break;
  631.          default:
  632.             _mesa_problem(NULL, "error in PrintTexture\n");
  633.             return;
  634.       }
  635.  
  636.       for (i = 0; i < img->Height; i++) {
  637.          for (j = 0; j < img->Width; j++) {
  638.             if (c==1)
  639.                printf("%02x  ", data[0]);
  640.             else if (c==2)
  641.                printf("%02x%02x  ", data[0], data[1]);
  642.             else if (c==3)
  643.                printf("%02x%02x%02x  ", data[0], data[1], data[2]);
  644.             else if (c==4)
  645.                printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
  646.             data += (srcRowStride - img->Width) * c;
  647.          }
  648.          /* XXX use img->ImageStride here */
  649.          printf("\n");
  650.  
  651.       }
  652.    }
  653.  
  654.    ctx->Driver.UnmapTextureImage(ctx, img, slice);
  655. }
  656.