1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26b8e80941Smrg#include <stdio.h>
27b8e80941Smrg#include "errors.h"
28848b8605Smrg#include "mtypes.h"
29848b8605Smrg#include "attrib.h"
30848b8605Smrg#include "enums.h"
31848b8605Smrg#include "formats.h"
32848b8605Smrg#include "hash.h"
33848b8605Smrg#include "imports.h"
34b8e80941Smrg#include "macros.h"
35848b8605Smrg#include "debug.h"
36848b8605Smrg#include "get.h"
37848b8605Smrg#include "pixelstore.h"
38848b8605Smrg#include "readpix.h"
39848b8605Smrg#include "texobj.h"
40848b8605Smrg
41848b8605Smrg
42848b8605Smrgstatic const char *
43848b8605Smrgtex_target_name(GLenum tgt)
44848b8605Smrg{
45848b8605Smrg   static const struct {
46848b8605Smrg      GLenum target;
47848b8605Smrg      const char *name;
48848b8605Smrg   } tex_targets[] = {
49848b8605Smrg      { GL_TEXTURE_1D, "GL_TEXTURE_1D" },
50848b8605Smrg      { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
51848b8605Smrg      { GL_TEXTURE_3D, "GL_TEXTURE_3D" },
52848b8605Smrg      { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
53848b8605Smrg      { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" },
54848b8605Smrg      { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" },
55848b8605Smrg      { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" },
56848b8605Smrg      { GL_TEXTURE_CUBE_MAP_ARRAY, "GL_TEXTURE_CUBE_MAP_ARRAY" },
57848b8605Smrg      { GL_TEXTURE_BUFFER, "GL_TEXTURE_BUFFER" },
58848b8605Smrg      { GL_TEXTURE_2D_MULTISAMPLE, "GL_TEXTURE_2D_MULTISAMPLE" },
59848b8605Smrg      { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "GL_TEXTURE_2D_MULTISAMPLE_ARRAY" },
60848b8605Smrg      { GL_TEXTURE_EXTERNAL_OES, "GL_TEXTURE_EXTERNAL_OES" }
61848b8605Smrg   };
62848b8605Smrg   GLuint i;
63b8e80941Smrg   STATIC_ASSERT(ARRAY_SIZE(tex_targets) == NUM_TEXTURE_TARGETS);
64b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(tex_targets); i++) {
65848b8605Smrg      if (tex_targets[i].target == tgt)
66848b8605Smrg         return tex_targets[i].name;
67848b8605Smrg   }
68848b8605Smrg   return "UNKNOWN TEX TARGET";
69848b8605Smrg}
70848b8605Smrg
71848b8605Smrg
72848b8605Smrgvoid
73848b8605Smrg_mesa_print_state( const char *msg, GLuint state )
74848b8605Smrg{
75848b8605Smrg   _mesa_debug(NULL,
76848b8605Smrg	   "%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",
77848b8605Smrg	   msg,
78848b8605Smrg	   state,
79848b8605Smrg	   (state & _NEW_MODELVIEW)       ? "ctx->ModelView, " : "",
80848b8605Smrg	   (state & _NEW_PROJECTION)      ? "ctx->Projection, " : "",
81848b8605Smrg	   (state & _NEW_TEXTURE_MATRIX)  ? "ctx->TextureMatrix, " : "",
82848b8605Smrg	   (state & _NEW_COLOR)           ? "ctx->Color, " : "",
83848b8605Smrg	   (state & _NEW_DEPTH)           ? "ctx->Depth, " : "",
84848b8605Smrg	   (state & _NEW_EVAL)            ? "ctx->Eval/EvalMap, " : "",
85848b8605Smrg	   (state & _NEW_FOG)             ? "ctx->Fog, " : "",
86848b8605Smrg	   (state & _NEW_HINT)            ? "ctx->Hint, " : "",
87848b8605Smrg	   (state & _NEW_LIGHT)           ? "ctx->Light, " : "",
88848b8605Smrg	   (state & _NEW_LINE)            ? "ctx->Line, " : "",
89848b8605Smrg	   (state & _NEW_PIXEL)           ? "ctx->Pixel, " : "",
90848b8605Smrg	   (state & _NEW_POINT)           ? "ctx->Point, " : "",
91848b8605Smrg	   (state & _NEW_POLYGON)         ? "ctx->Polygon, " : "",
92848b8605Smrg	   (state & _NEW_POLYGONSTIPPLE)  ? "ctx->PolygonStipple, " : "",
93848b8605Smrg	   (state & _NEW_SCISSOR)         ? "ctx->Scissor, " : "",
94848b8605Smrg	   (state & _NEW_STENCIL)         ? "ctx->Stencil, " : "",
95b8e80941Smrg	   (state & _NEW_TEXTURE_OBJECT)  ? "ctx->Texture(Object), " : "",
96848b8605Smrg	   (state & _NEW_TRANSFORM)       ? "ctx->Transform, " : "",
97848b8605Smrg	   (state & _NEW_VIEWPORT)        ? "ctx->Viewport, " : "",
98b8e80941Smrg           (state & _NEW_TEXTURE_STATE)   ? "ctx->Texture(State), " : "",
99848b8605Smrg	   (state & _NEW_RENDERMODE)      ? "ctx->RenderMode, " : "",
100848b8605Smrg	   (state & _NEW_BUFFERS)         ? "ctx->Visual, ctx->DrawBuffer,, " : "");
101848b8605Smrg}
102848b8605Smrg
103848b8605Smrg
104848b8605Smrg
105848b8605Smrg/**
106848b8605Smrg * Print information about this Mesa version and build options.
107848b8605Smrg */
108848b8605Smrgvoid _mesa_print_info( struct gl_context *ctx )
109848b8605Smrg{
110848b8605Smrg   _mesa_debug(NULL, "Mesa GL_VERSION = %s\n",
111848b8605Smrg	   (char *) _mesa_GetString(GL_VERSION));
112848b8605Smrg   _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n",
113848b8605Smrg	   (char *) _mesa_GetString(GL_RENDERER));
114848b8605Smrg   _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n",
115848b8605Smrg	   (char *) _mesa_GetString(GL_VENDOR));
116848b8605Smrg
117848b8605Smrg   /* use ctx as GL_EXTENSIONS will not work on 3.0 or higher
118848b8605Smrg    * core contexts.
119848b8605Smrg    */
120848b8605Smrg   _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", ctx->Extensions.String);
121848b8605Smrg
122848b8605Smrg#if defined(USE_X86_ASM)
123848b8605Smrg   _mesa_debug(NULL, "Mesa x86-optimized: YES\n");
124848b8605Smrg#else
125848b8605Smrg   _mesa_debug(NULL, "Mesa x86-optimized: NO\n");
126848b8605Smrg#endif
127848b8605Smrg#if defined(USE_SPARC_ASM)
128848b8605Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: YES\n");
129848b8605Smrg#else
130848b8605Smrg   _mesa_debug(NULL, "Mesa sparc-optimized: NO\n");
131848b8605Smrg#endif
132848b8605Smrg}
133848b8605Smrg
134848b8605Smrg
135848b8605Smrg/**
136848b8605Smrg * Set verbose logging flags.  When these flags are set, GL API calls
137848b8605Smrg * in the various categories will be printed to stderr.
138848b8605Smrg * \param str  a comma-separated list of keywords
139848b8605Smrg */
140848b8605Smrgstatic void
141848b8605Smrgset_verbose_flags(const char *str)
142848b8605Smrg{
143848b8605Smrg#ifdef DEBUG
144848b8605Smrg   struct option {
145848b8605Smrg      const char *name;
146848b8605Smrg      GLbitfield flag;
147848b8605Smrg   };
148848b8605Smrg   static const struct option opts[] = {
149848b8605Smrg      { "varray",    VERBOSE_VARRAY },
150848b8605Smrg      { "tex",       VERBOSE_TEXTURE },
151848b8605Smrg      { "mat",       VERBOSE_MATERIAL },
152848b8605Smrg      { "pipe",      VERBOSE_PIPELINE },
153848b8605Smrg      { "driver",    VERBOSE_DRIVER },
154848b8605Smrg      { "state",     VERBOSE_STATE },
155848b8605Smrg      { "api",       VERBOSE_API },
156848b8605Smrg      { "list",      VERBOSE_DISPLAY_LIST },
157848b8605Smrg      { "lighting",  VERBOSE_LIGHTING },
158848b8605Smrg      { "disassem",  VERBOSE_DISASSEM },
159848b8605Smrg      { "draw",      VERBOSE_DRAW },
160848b8605Smrg      { "swap",      VERBOSE_SWAPBUFFERS }
161848b8605Smrg   };
162848b8605Smrg   GLuint i;
163848b8605Smrg
164848b8605Smrg   if (!str)
165848b8605Smrg      return;
166848b8605Smrg
167848b8605Smrg   MESA_VERBOSE = 0x0;
168b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(opts); i++) {
169848b8605Smrg      if (strstr(str, opts[i].name) || strcmp(str, "all") == 0)
170848b8605Smrg         MESA_VERBOSE |= opts[i].flag;
171848b8605Smrg   }
172848b8605Smrg#endif
173848b8605Smrg}
174848b8605Smrg
175848b8605Smrg
176848b8605Smrg/**
177848b8605Smrg * Set debugging flags.  When these flags are set, Mesa will do additional
178848b8605Smrg * debug checks or actions.
179848b8605Smrg * \param str  a comma-separated list of keywords
180848b8605Smrg */
181848b8605Smrgstatic void
182848b8605Smrgset_debug_flags(const char *str)
183848b8605Smrg{
184848b8605Smrg#ifdef DEBUG
185848b8605Smrg   struct option {
186848b8605Smrg      const char *name;
187848b8605Smrg      GLbitfield flag;
188848b8605Smrg   };
189848b8605Smrg   static const struct option opts[] = {
190848b8605Smrg      { "silent", DEBUG_SILENT }, /* turn off debug messages */
191848b8605Smrg      { "flush", DEBUG_ALWAYS_FLUSH }, /* flush after each drawing command */
192848b8605Smrg      { "incomplete_tex", DEBUG_INCOMPLETE_TEXTURE },
193b8e80941Smrg      { "incomplete_fbo", DEBUG_INCOMPLETE_FBO },
194b8e80941Smrg      { "context", DEBUG_CONTEXT } /* force set GL_CONTEXT_FLAG_DEBUG_BIT flag */
195848b8605Smrg   };
196848b8605Smrg   GLuint i;
197848b8605Smrg
198848b8605Smrg   if (!str)
199848b8605Smrg      return;
200848b8605Smrg
201848b8605Smrg   MESA_DEBUG_FLAGS = 0x0;
202b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(opts); i++) {
203848b8605Smrg      if (strstr(str, opts[i].name))
204848b8605Smrg         MESA_DEBUG_FLAGS |= opts[i].flag;
205848b8605Smrg   }
206848b8605Smrg#endif
207848b8605Smrg}
208848b8605Smrg
209848b8605Smrg
210848b8605Smrg/**
211848b8605Smrg * Initialize debugging variables from env vars.
212848b8605Smrg */
213848b8605Smrgvoid
214848b8605Smrg_mesa_init_debug( struct gl_context *ctx )
215848b8605Smrg{
216b8e80941Smrg   set_debug_flags(getenv("MESA_DEBUG"));
217b8e80941Smrg   set_verbose_flags(getenv("MESA_VERBOSE"));
218848b8605Smrg}
219848b8605Smrg
220848b8605Smrg
221848b8605Smrg/*
222848b8605Smrg * Write ppm file
223848b8605Smrg */
224848b8605Smrgstatic void
225848b8605Smrgwrite_ppm(const char *filename, const GLubyte *buffer, int width, int height,
226848b8605Smrg          int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
227848b8605Smrg{
228848b8605Smrg   FILE *f = fopen( filename, "w" );
229848b8605Smrg   if (f) {
230848b8605Smrg      int x, y;
231848b8605Smrg      const GLubyte *ptr = buffer;
232848b8605Smrg      fprintf(f,"P6\n");
233848b8605Smrg      fprintf(f,"# ppm-file created by osdemo.c\n");
234848b8605Smrg      fprintf(f,"%i %i\n", width,height);
235848b8605Smrg      fprintf(f,"255\n");
236848b8605Smrg      fclose(f);
237848b8605Smrg      f = fopen( filename, "ab" );  /* reopen in binary append mode */
238b8e80941Smrg      if (!f) {
239b8e80941Smrg         fprintf(stderr, "Error while reopening %s in write_ppm()\n",
240b8e80941Smrg                 filename);
241b8e80941Smrg         return;
242b8e80941Smrg      }
243848b8605Smrg      for (y=0; y < height; y++) {
244848b8605Smrg         for (x = 0; x < width; x++) {
245848b8605Smrg            int yy = invert ? (height - 1 - y) : y;
246848b8605Smrg            int i = (yy * width + x) * comps;
247848b8605Smrg            fputc(ptr[i+rcomp], f); /* write red */
248848b8605Smrg            fputc(ptr[i+gcomp], f); /* write green */
249848b8605Smrg            fputc(ptr[i+bcomp], f); /* write blue */
250848b8605Smrg         }
251848b8605Smrg      }
252848b8605Smrg      fclose(f);
253848b8605Smrg   }
254848b8605Smrg   else {
255848b8605Smrg      fprintf(stderr, "Unable to create %s in write_ppm()\n", filename);
256848b8605Smrg   }
257848b8605Smrg}
258848b8605Smrg
259848b8605Smrg
260848b8605Smrg/**
261848b8605Smrg * Write a texture image to a ppm file.
262848b8605Smrg * \param face  cube face in [0,5]
263848b8605Smrg * \param level  mipmap level
264848b8605Smrg */
265848b8605Smrgstatic void
266848b8605Smrgwrite_texture_image(struct gl_texture_object *texObj,
267848b8605Smrg                    GLuint face, GLuint level)
268848b8605Smrg{
269848b8605Smrg   struct gl_texture_image *img = texObj->Image[face][level];
270848b8605Smrg   if (img) {
271848b8605Smrg      GET_CURRENT_CONTEXT(ctx);
272848b8605Smrg      struct gl_pixelstore_attrib store;
273848b8605Smrg      GLubyte *buffer;
274848b8605Smrg      char s[100];
275848b8605Smrg
276848b8605Smrg      buffer = malloc(img->Width * img->Height
277848b8605Smrg                                        * img->Depth * 4);
278848b8605Smrg
279848b8605Smrg      store = ctx->Pack; /* save */
280848b8605Smrg      ctx->Pack = ctx->DefaultPacking;
281848b8605Smrg
282b8e80941Smrg      ctx->Driver.GetTexSubImage(ctx,
283b8e80941Smrg                                 0, 0, 0, img->Width, img->Height, img->Depth,
284b8e80941Smrg                                 GL_RGBA, GL_UNSIGNED_BYTE, buffer, img);
285848b8605Smrg
286848b8605Smrg      /* make filename */
287848b8605Smrg      _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
288848b8605Smrg
289848b8605Smrg      printf("  Writing image level %u to %s\n", level, s);
290848b8605Smrg      write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
291848b8605Smrg
292848b8605Smrg      ctx->Pack = store; /* restore */
293848b8605Smrg
294848b8605Smrg      free(buffer);
295848b8605Smrg   }
296848b8605Smrg}
297848b8605Smrg
298848b8605Smrg
299848b8605Smrg/**
300848b8605Smrg * Write renderbuffer image to a ppm file.
301848b8605Smrg */
302848b8605Smrgvoid
303848b8605Smrg_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb)
304848b8605Smrg{
305848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
306848b8605Smrg   GLubyte *buffer;
307848b8605Smrg   char s[100];
308848b8605Smrg   GLenum format, type;
309848b8605Smrg
310848b8605Smrg   if (rb->_BaseFormat == GL_RGB ||
311848b8605Smrg       rb->_BaseFormat == GL_RGBA) {
312848b8605Smrg      format = GL_RGBA;
313848b8605Smrg      type = GL_UNSIGNED_BYTE;
314848b8605Smrg   }
315848b8605Smrg   else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
316848b8605Smrg      format = GL_DEPTH_STENCIL;
317848b8605Smrg      type = GL_UNSIGNED_INT_24_8;
318848b8605Smrg   }
319848b8605Smrg   else {
320848b8605Smrg      _mesa_debug(NULL,
321848b8605Smrg                  "Unsupported BaseFormat 0x%x in "
322848b8605Smrg                  "_mesa_write_renderbuffer_image()\n",
323848b8605Smrg                  rb->_BaseFormat);
324848b8605Smrg      return;
325848b8605Smrg   }
326848b8605Smrg
327848b8605Smrg   buffer = malloc(rb->Width * rb->Height * 4);
328848b8605Smrg
329848b8605Smrg   ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
330848b8605Smrg                          format, type, &ctx->DefaultPacking, buffer);
331848b8605Smrg
332848b8605Smrg   /* make filename */
333848b8605Smrg   _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
334848b8605Smrg   _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name);
335848b8605Smrg
336848b8605Smrg   printf("  Writing renderbuffer image to %s\n", s);
337848b8605Smrg
338848b8605Smrg   _mesa_debug(NULL, "  Writing renderbuffer image to %s\n", s);
339848b8605Smrg
340848b8605Smrg   write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
341848b8605Smrg
342848b8605Smrg   free(buffer);
343848b8605Smrg}
344848b8605Smrg
345848b8605Smrg
346848b8605Smrg/** How many texture images (mipmap levels, faces) to write to files */
347848b8605Smrg#define WRITE_NONE 0
348848b8605Smrg#define WRITE_ONE  1
349848b8605Smrg#define WRITE_ALL  2
350848b8605Smrg
351848b8605Smrgstatic GLuint WriteImages;
352848b8605Smrg
353848b8605Smrg
354848b8605Smrgstatic void
355848b8605Smrgdump_texture(struct gl_texture_object *texObj, GLuint writeImages)
356848b8605Smrg{
357848b8605Smrg   const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
358848b8605Smrg   GLboolean written = GL_FALSE;
359848b8605Smrg   GLuint i, j;
360848b8605Smrg
361848b8605Smrg   printf("Texture %u\n", texObj->Name);
362848b8605Smrg   printf("  Target %s\n", tex_target_name(texObj->Target));
363848b8605Smrg   for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
364848b8605Smrg      for (j = 0; j < numFaces; j++) {
365848b8605Smrg         struct gl_texture_image *texImg = texObj->Image[j][i];
366848b8605Smrg         if (texImg) {
367848b8605Smrg            printf("  Face %u level %u: %d x %d x %d, format %s\n",
368848b8605Smrg		   j, i,
369848b8605Smrg		   texImg->Width, texImg->Height, texImg->Depth,
370848b8605Smrg		   _mesa_get_format_name(texImg->TexFormat));
371848b8605Smrg            if (writeImages == WRITE_ALL ||
372848b8605Smrg                (writeImages == WRITE_ONE && !written)) {
373848b8605Smrg               write_texture_image(texObj, j, i);
374848b8605Smrg               written = GL_TRUE;
375848b8605Smrg            }
376848b8605Smrg         }
377848b8605Smrg      }
378848b8605Smrg   }
379848b8605Smrg}
380848b8605Smrg
381848b8605Smrg
382848b8605Smrg/**
383848b8605Smrg * Dump a single texture.
384848b8605Smrg */
385848b8605Smrgvoid
386848b8605Smrg_mesa_dump_texture(GLuint texture, GLuint writeImages)
387848b8605Smrg{
388848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
389848b8605Smrg   struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
390848b8605Smrg   if (texObj) {
391848b8605Smrg      dump_texture(texObj, writeImages);
392848b8605Smrg   }
393848b8605Smrg}
394848b8605Smrg
395848b8605Smrg
396848b8605Smrgstatic void
397848b8605Smrgdump_texture_cb(GLuint id, void *data, void *userData)
398848b8605Smrg{
399848b8605Smrg   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
400848b8605Smrg   (void) userData;
401848b8605Smrg   dump_texture(texObj, WriteImages);
402848b8605Smrg}
403848b8605Smrg
404848b8605Smrg
405848b8605Smrg/**
406848b8605Smrg * Print basic info about all texture objext to stdout.
407848b8605Smrg * If dumpImages is true, write PPM of level[0] image to a file.
408848b8605Smrg */
409848b8605Smrgvoid
410848b8605Smrg_mesa_dump_textures(GLuint writeImages)
411848b8605Smrg{
412848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
413848b8605Smrg   WriteImages = writeImages;
414848b8605Smrg   _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
415848b8605Smrg}
416848b8605Smrg
417848b8605Smrg
418848b8605Smrgstatic void
419848b8605Smrgdump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
420848b8605Smrg{
421848b8605Smrg   printf("Renderbuffer %u: %u x %u  IntFormat = %s\n",
422848b8605Smrg	  rb->Name, rb->Width, rb->Height,
423b8e80941Smrg	  _mesa_enum_to_string(rb->InternalFormat));
424848b8605Smrg   if (writeImage) {
425848b8605Smrg      _mesa_write_renderbuffer_image(rb);
426848b8605Smrg   }
427848b8605Smrg}
428848b8605Smrg
429848b8605Smrg
430848b8605Smrgstatic void
431848b8605Smrgdump_renderbuffer_cb(GLuint id, void *data, void *userData)
432848b8605Smrg{
433848b8605Smrg   const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
434848b8605Smrg   (void) userData;
435848b8605Smrg   dump_renderbuffer(rb, WriteImages);
436848b8605Smrg}
437848b8605Smrg
438848b8605Smrg
439848b8605Smrg/**
440848b8605Smrg * Print basic info about all renderbuffers to stdout.
441848b8605Smrg * If dumpImages is true, write PPM of level[0] image to a file.
442848b8605Smrg */
443848b8605Smrgvoid
444848b8605Smrg_mesa_dump_renderbuffers(GLboolean writeImages)
445848b8605Smrg{
446848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
447848b8605Smrg   WriteImages = writeImages;
448848b8605Smrg   _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
449848b8605Smrg}
450848b8605Smrg
451848b8605Smrg
452848b8605Smrg
453848b8605Smrgvoid
454848b8605Smrg_mesa_dump_color_buffer(const char *filename)
455848b8605Smrg{
456848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
457848b8605Smrg   const GLuint w = ctx->DrawBuffer->Width;
458848b8605Smrg   const GLuint h = ctx->DrawBuffer->Height;
459848b8605Smrg   GLubyte *buf;
460848b8605Smrg
461848b8605Smrg   buf = malloc(w * h * 4);
462848b8605Smrg
463848b8605Smrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
464848b8605Smrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
465848b8605Smrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
466848b8605Smrg
467848b8605Smrg   _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
468848b8605Smrg
469848b8605Smrg   printf("ReadBuffer %p 0x%x  DrawBuffer %p 0x%x\n",
470848b8605Smrg	  (void *) ctx->ReadBuffer->_ColorReadBuffer,
471848b8605Smrg	  ctx->ReadBuffer->ColorReadBuffer,
472848b8605Smrg	  (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
473848b8605Smrg	  ctx->DrawBuffer->ColorDrawBuffer[0]);
474848b8605Smrg   printf("Writing %d x %d color buffer to %s\n", w, h, filename);
475848b8605Smrg   write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
476848b8605Smrg
477848b8605Smrg   _mesa_PopClientAttrib();
478848b8605Smrg
479848b8605Smrg   free(buf);
480848b8605Smrg}
481848b8605Smrg
482848b8605Smrg
483848b8605Smrgvoid
484848b8605Smrg_mesa_dump_depth_buffer(const char *filename)
485848b8605Smrg{
486848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
487848b8605Smrg   const GLuint w = ctx->DrawBuffer->Width;
488848b8605Smrg   const GLuint h = ctx->DrawBuffer->Height;
489848b8605Smrg   GLuint *buf;
490848b8605Smrg   GLubyte *buf2;
491848b8605Smrg   GLuint i;
492848b8605Smrg
493848b8605Smrg   buf = malloc(w * h * 4);  /* 4 bpp */
494848b8605Smrg   buf2 = malloc(w * h * 3); /* 3 bpp */
495848b8605Smrg
496848b8605Smrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
497848b8605Smrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
498848b8605Smrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
499848b8605Smrg
500848b8605Smrg   _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
501848b8605Smrg
502848b8605Smrg   /* spread 24 bits of Z across R, G, B */
503848b8605Smrg   for (i = 0; i < w * h; i++) {
504848b8605Smrg      buf2[i*3+0] = (buf[i] >> 24) & 0xff;
505848b8605Smrg      buf2[i*3+1] = (buf[i] >> 16) & 0xff;
506848b8605Smrg      buf2[i*3+2] = (buf[i] >>  8) & 0xff;
507848b8605Smrg   }
508848b8605Smrg
509848b8605Smrg   printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
510848b8605Smrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
511848b8605Smrg
512848b8605Smrg   _mesa_PopClientAttrib();
513848b8605Smrg
514848b8605Smrg   free(buf);
515848b8605Smrg   free(buf2);
516848b8605Smrg}
517848b8605Smrg
518848b8605Smrg
519848b8605Smrgvoid
520848b8605Smrg_mesa_dump_stencil_buffer(const char *filename)
521848b8605Smrg{
522848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
523848b8605Smrg   const GLuint w = ctx->DrawBuffer->Width;
524848b8605Smrg   const GLuint h = ctx->DrawBuffer->Height;
525848b8605Smrg   GLubyte *buf;
526848b8605Smrg   GLubyte *buf2;
527848b8605Smrg   GLuint i;
528848b8605Smrg
529848b8605Smrg   buf = malloc(w * h);  /* 1 bpp */
530848b8605Smrg   buf2 = malloc(w * h * 3); /* 3 bpp */
531848b8605Smrg
532848b8605Smrg   _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
533848b8605Smrg   _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
534848b8605Smrg   _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
535848b8605Smrg
536848b8605Smrg   _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
537848b8605Smrg
538848b8605Smrg   for (i = 0; i < w * h; i++) {
539848b8605Smrg      buf2[i*3+0] = buf[i];
540848b8605Smrg      buf2[i*3+1] = (buf[i] & 127) * 2;
541848b8605Smrg      buf2[i*3+2] = (buf[i] - 128) * 2;
542848b8605Smrg   }
543848b8605Smrg
544848b8605Smrg   printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
545848b8605Smrg   write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
546848b8605Smrg
547848b8605Smrg   _mesa_PopClientAttrib();
548848b8605Smrg
549848b8605Smrg   free(buf);
550848b8605Smrg   free(buf2);
551848b8605Smrg}
552848b8605Smrg
553848b8605Smrg
554848b8605Smrgvoid
555848b8605Smrg_mesa_dump_image(const char *filename, const void *image, GLuint w, GLuint h,
556848b8605Smrg                 GLenum format, GLenum type)
557848b8605Smrg{
558848b8605Smrg   GLboolean invert = GL_TRUE;
559848b8605Smrg
560848b8605Smrg   if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
561848b8605Smrg      write_ppm(filename, image, w, h, 4, 0, 1, 2, invert);
562848b8605Smrg   }
563848b8605Smrg   else if (format == GL_BGRA && type == GL_UNSIGNED_BYTE) {
564848b8605Smrg      write_ppm(filename, image, w, h, 4, 2, 1, 0, invert);
565848b8605Smrg   }
566848b8605Smrg   else if (format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE) {
567848b8605Smrg      write_ppm(filename, image, w, h, 2, 1, 0, 0, invert);
568848b8605Smrg   }
569848b8605Smrg   else if (format == GL_RED && type == GL_UNSIGNED_BYTE) {
570848b8605Smrg      write_ppm(filename, image, w, h, 1, 0, 0, 0, invert);
571848b8605Smrg   }
572848b8605Smrg   else if (format == GL_RGBA && type == GL_FLOAT) {
573848b8605Smrg      /* convert floats to ubyte */
574848b8605Smrg      GLubyte *buf = malloc(w * h * 4 * sizeof(GLubyte));
575848b8605Smrg      const GLfloat *f = (const GLfloat *) image;
576848b8605Smrg      GLuint i;
577848b8605Smrg      for (i = 0; i < w * h * 4; i++) {
578848b8605Smrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
579848b8605Smrg      }
580848b8605Smrg      write_ppm(filename, buf, w, h, 4, 0, 1, 2, invert);
581848b8605Smrg      free(buf);
582848b8605Smrg   }
583848b8605Smrg   else if (format == GL_RED && type == GL_FLOAT) {
584848b8605Smrg      /* convert floats to ubyte */
585848b8605Smrg      GLubyte *buf = malloc(w * h * sizeof(GLubyte));
586848b8605Smrg      const GLfloat *f = (const GLfloat *) image;
587848b8605Smrg      GLuint i;
588848b8605Smrg      for (i = 0; i < w * h; i++) {
589848b8605Smrg         UNCLAMPED_FLOAT_TO_UBYTE(buf[i], f[i]);
590848b8605Smrg      }
591848b8605Smrg      write_ppm(filename, buf, w, h, 1, 0, 0, 0, invert);
592848b8605Smrg      free(buf);
593848b8605Smrg   }
594848b8605Smrg   else {
595848b8605Smrg      _mesa_problem(NULL,
596848b8605Smrg                 "Unsupported format 0x%x / type 0x%x in _mesa_dump_image()",
597848b8605Smrg                 format, type);
598848b8605Smrg   }
599848b8605Smrg}
600848b8605Smrg
601848b8605Smrg
602848b8605Smrg/**
603848b8605Smrg * Quick and dirty function to "print" a texture to stdout.
604848b8605Smrg */
605848b8605Smrgvoid
606848b8605Smrg_mesa_print_texture(struct gl_context *ctx, struct gl_texture_image *img)
607848b8605Smrg{
608848b8605Smrg   const GLint slice = 0;
609848b8605Smrg   GLint srcRowStride;
610848b8605Smrg   GLuint i, j, c;
611848b8605Smrg   GLubyte *data;
612848b8605Smrg
613848b8605Smrg   ctx->Driver.MapTextureImage(ctx, img, slice,
614848b8605Smrg                               0, 0, img->Width, img->Height, GL_MAP_READ_BIT,
615848b8605Smrg                               &data, &srcRowStride);
616848b8605Smrg
617848b8605Smrg   if (!data) {
618848b8605Smrg      printf("No texture data\n");
619848b8605Smrg   }
620848b8605Smrg   else {
621848b8605Smrg      /* XXX add more formats or make into a new format utility function */
622848b8605Smrg      switch (img->TexFormat) {
623848b8605Smrg         case MESA_FORMAT_A_UNORM8:
624848b8605Smrg         case MESA_FORMAT_L_UNORM8:
625848b8605Smrg         case MESA_FORMAT_I_UNORM8:
626848b8605Smrg            c = 1;
627848b8605Smrg            break;
628848b8605Smrg         case MESA_FORMAT_L8A8_UNORM:
629848b8605Smrg         case MESA_FORMAT_A8L8_UNORM:
630848b8605Smrg            c = 2;
631848b8605Smrg            break;
632848b8605Smrg         case MESA_FORMAT_BGR_UNORM8:
633848b8605Smrg         case MESA_FORMAT_RGB_UNORM8:
634848b8605Smrg            c = 3;
635848b8605Smrg            break;
636848b8605Smrg         case MESA_FORMAT_A8B8G8R8_UNORM:
637848b8605Smrg         case MESA_FORMAT_B8G8R8A8_UNORM:
638848b8605Smrg            c = 4;
639848b8605Smrg            break;
640848b8605Smrg         default:
641848b8605Smrg            _mesa_problem(NULL, "error in PrintTexture\n");
642848b8605Smrg            return;
643848b8605Smrg      }
644848b8605Smrg
645848b8605Smrg      for (i = 0; i < img->Height; i++) {
646848b8605Smrg         for (j = 0; j < img->Width; j++) {
647848b8605Smrg            if (c==1)
648848b8605Smrg               printf("%02x  ", data[0]);
649848b8605Smrg            else if (c==2)
650848b8605Smrg               printf("%02x%02x  ", data[0], data[1]);
651848b8605Smrg            else if (c==3)
652848b8605Smrg               printf("%02x%02x%02x  ", data[0], data[1], data[2]);
653848b8605Smrg            else if (c==4)
654848b8605Smrg               printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
655848b8605Smrg            data += (srcRowStride - img->Width) * c;
656848b8605Smrg         }
657848b8605Smrg         /* XXX use img->ImageStride here */
658848b8605Smrg         printf("\n");
659848b8605Smrg
660848b8605Smrg      }
661848b8605Smrg   }
662848b8605Smrg
663848b8605Smrg   ctx->Driver.UnmapTextureImage(ctx, img, slice);
664848b8605Smrg}
665