u_debug.c revision 8c4bd92b68cf79ff94dc431f78a970bbab7e0d00
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright (c) 2008 VMware, Inc.
5 * 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
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29
30#include "pipe/p_config.h"
31
32#include <stdarg.h>
33
34
35#ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
36
37#include <windows.h>
38#include <winddi.h>
39
40#elif defined(PIPE_SUBSYSTEM_WINDOWS_CE)
41
42#include <stdio.h>
43#include <stdlib.h>
44#include <windows.h>
45#include <types.h>
46
47#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
48
49#ifndef WIN32_LEAN_AND_MEAN
50#define WIN32_LEAN_AND_MEAN      // Exclude rarely-used stuff from Windows headers
51#endif
52#include <windows.h>
53#include <stdio.h>
54
55#else
56
57#include <stdio.h>
58#include <stdlib.h>
59
60#endif
61
62#include "pipe/p_compiler.h"
63#include "util/u_debug.h"
64#include "pipe/p_format.h"
65#include "pipe/p_state.h"
66#include "pipe/p_inlines.h"
67#include "util/u_memory.h"
68#include "util/u_string.h"
69#include "util/u_stream.h"
70#include "util/u_math.h"
71#include "util/u_tile.h"
72
73
74#ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
75static INLINE void
76_EngDebugPrint(const char *format, ...)
77{
78   va_list ap;
79   va_start(ap, format);
80   EngDebugPrint("", (PCHAR)format, ap);
81   va_end(ap);
82}
83#endif
84
85
86void _debug_vprintf(const char *format, va_list ap)
87{
88#if defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
89   /* EngDebugPrint does not handle float point arguments, so we need to use
90    * our own vsnprintf implementation. It is also very slow, so buffer until
91    * we find a newline. */
92   static char buf[512] = {'\0'};
93   size_t len = strlen(buf);
94   int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
95   if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
96      _EngDebugPrint("%s", buf);
97      buf[0] = '\0';
98   }
99#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
100   /* EngDebugPrint does not handle float point arguments, so we need to use
101    * our own vsnprintf implementation. It is also very slow, so buffer until
102    * we find a newline. */
103   static char buf[512 + 1] = {'\0'};
104   size_t len = strlen(buf);
105   int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
106   if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
107      OutputDebugStringA(buf);
108      buf[0] = '\0';
109   }
110
111   if(GetConsoleWindow() && !IsDebuggerPresent()) {
112      vfprintf(stderr, format, ap);
113      fflush(stderr);
114   }
115
116#elif defined(PIPE_SUBSYSTEM_WINDOWS_CE)
117   wchar_t *wide_format;
118   long wide_str_len;
119   char buf[512];
120   int ret;
121#if (_WIN32_WCE < 600)
122   ret = vsprintf(buf, format, ap);
123   if(ret < 0){
124       sprintf(buf, "Cant handle debug print!");
125       ret = 25;
126   }
127#else
128   ret = vsprintf_s(buf, 512, format, ap);
129   if(ret < 0){
130       sprintf_s(buf, 512, "Cant handle debug print!");
131       ret = 25;
132   }
133#endif
134   buf[ret] = '\0';
135   /* Format is ascii - needs to be converted to wchar_t for printing */
136   wide_str_len = MultiByteToWideChar(CP_ACP, 0, (const char *) buf, -1, NULL, 0);
137   wide_format = (wchar_t *) malloc((wide_str_len+1) * sizeof(wchar_t));
138   if (wide_format) {
139      MultiByteToWideChar(CP_ACP, 0, (const char *) buf, -1,
140            wide_format, wide_str_len);
141      NKDbgPrintfW(wide_format, wide_format);
142      free(wide_format);
143   }
144#elif defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)
145   /* TODO */
146#else /* !PIPE_SUBSYSTEM_WINDOWS */
147#ifdef DEBUG
148   vfprintf(stderr, format, ap);
149#endif
150#endif
151}
152
153
154#ifdef DEBUG
155void debug_print_blob( const char *name,
156                       const void *blob,
157                       unsigned size )
158{
159   const unsigned *ublob = (const unsigned *)blob;
160   unsigned i;
161
162   debug_printf("%s (%d dwords%s)\n", name, size/4,
163                size%4 ? "... plus a few bytes" : "");
164
165   for (i = 0; i < size/4; i++) {
166      debug_printf("%d:\t%08x\n", i, ublob[i]);
167   }
168}
169#endif
170
171
172#ifndef debug_break
173void debug_break(void)
174{
175#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
176   DebugBreak();
177#elif defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
178   EngDebugBreak();
179#else
180   abort();
181#endif
182}
183#endif
184
185
186#ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
187static const char *
188find(const char *start, const char *end, char c)
189{
190   const char *p;
191   for(p = start; !end || p != end; ++p) {
192      if(*p == c)
193	 return p;
194      if(*p < 32)
195	 break;
196   }
197   return NULL;
198}
199
200static int
201compare(const char *start, const char *end, const char *s)
202{
203   const char *p, *q;
204   for(p = start, q = s; p != end && *q != '\0'; ++p, ++q) {
205      if(*p != *q)
206	 return 0;
207   }
208   return p == end && *q == '\0';
209}
210
211static void
212copy(char *dst, const char *start, const char *end, size_t n)
213{
214   const char *p;
215   char *q;
216   for(p = start, q = dst, n = n - 1; p != end && n; ++p, ++q, --n)
217      *q = *p;
218   *q = '\0';
219}
220#endif
221
222
223static INLINE const char *
224_debug_get_option(const char *name)
225{
226#if defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
227   /* EngMapFile creates the file if it does not exists, so it must either be
228    * disabled on release versions (or put in a less conspicuous place). */
229#ifdef DEBUG
230   const char *result = NULL;
231   ULONG_PTR iFile = 0;
232   const void *pMap = NULL;
233   const char *sol, *eol, *sep;
234   static char output[1024];
235
236   pMap = EngMapFile(L"\\??\\c:\\gallium.cfg", 0, &iFile);
237   if(pMap) {
238      sol = (const char *)pMap;
239      while(1) {
240	 /* TODO: handle LF line endings */
241	 eol = find(sol, NULL, '\r');
242	 if(!eol || eol == sol)
243	    break;
244	 sep = find(sol, eol, '=');
245	 if(!sep)
246	    break;
247	 if(compare(sol, sep, name)) {
248	    copy(output, sep + 1, eol, sizeof(output));
249	    result = output;
250	    break;
251	 }
252	 sol = eol + 2;
253      }
254      EngUnmapFile(iFile);
255   }
256   return result;
257#else
258   return NULL;
259#endif
260#elif defined(PIPE_SUBSYSTEM_WINDOWS_CE) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)
261   /* TODO: implement */
262   return NULL;
263#else
264   return getenv(name);
265#endif
266}
267
268const char *
269debug_get_option(const char *name, const char *dfault)
270{
271   const char *result;
272
273   result = _debug_get_option(name);
274   if(!result)
275      result = dfault;
276
277   debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
278
279   return result;
280}
281
282boolean
283debug_get_bool_option(const char *name, boolean dfault)
284{
285   const char *str = _debug_get_option(name);
286   boolean result;
287
288   if(str == NULL)
289      result = dfault;
290   else if(!util_strcmp(str, "n"))
291      result = FALSE;
292   else if(!util_strcmp(str, "no"))
293      result = FALSE;
294   else if(!util_strcmp(str, "0"))
295      result = FALSE;
296   else if(!util_strcmp(str, "f"))
297      result = FALSE;
298   else if(!util_strcmp(str, "false"))
299      result = FALSE;
300   else
301      result = TRUE;
302
303   debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
304
305   return result;
306}
307
308
309long
310debug_get_num_option(const char *name, long dfault)
311{
312   long result;
313   const char *str;
314
315   str = _debug_get_option(name);
316   if(!str)
317      result = dfault;
318   else {
319      long sign;
320      char c;
321      c = *str++;
322      if(c == '-') {
323	 sign = -1;
324	 c = *str++;
325      }
326      else {
327	 sign = 1;
328      }
329      result = 0;
330      while('0' <= c && c <= '9') {
331	 result = result*10 + (c - '0');
332	 c = *str++;
333      }
334      result *= sign;
335   }
336
337   debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
338
339   return result;
340}
341
342
343unsigned long
344debug_get_flags_option(const char *name,
345                       const struct debug_named_value *flags,
346                       unsigned long dfault)
347{
348   unsigned long result;
349   const char *str;
350
351   str = _debug_get_option(name);
352   if(!str)
353      result = dfault;
354   else if (!util_strcmp(str, "help")) {
355      result = dfault;
356      while (flags->name) {
357         debug_printf("%s: help for %s: %s [0x%lx]\n", __FUNCTION__, name, flags->name, flags->value);
358         flags++;
359      }
360   }
361   else {
362      result = 0;
363      while( flags->name ) {
364	 if (!util_strcmp(str, "all") || util_strstr(str, flags->name ))
365	    result |= flags->value;
366	 ++flags;
367      }
368   }
369
370   if (str) {
371      debug_printf("%s: %s = 0x%lx (%s)\n", __FUNCTION__, name, result, str);
372   }
373   else {
374      debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
375   }
376
377   return result;
378}
379
380
381void _debug_assert_fail(const char *expr,
382                        const char *file,
383                        unsigned line,
384                        const char *function)
385{
386   _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
387#if defined(PIPE_OS_WINDOWS) && !defined(PIPE_SUBSYSTEM_WINDOWS_USER)
388   if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", FALSE))
389#else
390   if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", TRUE))
391#endif
392      debug_break();
393   else
394      _debug_printf("continuing...\n");
395}
396
397
398const char *
399debug_dump_enum(const struct debug_named_value *names,
400                unsigned long value)
401{
402   static char rest[64];
403
404   while(names->name) {
405      if(names->value == value)
406	 return names->name;
407      ++names;
408   }
409
410   util_snprintf(rest, sizeof(rest), "0x%08lx", value);
411   return rest;
412}
413
414
415const char *
416debug_dump_enum_noprefix(const struct debug_named_value *names,
417                         const char *prefix,
418                         unsigned long value)
419{
420   static char rest[64];
421
422   while(names->name) {
423      if(names->value == value) {
424         const char *name = names->name;
425         while (*name == *prefix) {
426            name++;
427            prefix++;
428         }
429         return name;
430      }
431      ++names;
432   }
433
434
435
436   util_snprintf(rest, sizeof(rest), "0x%08lx", value);
437   return rest;
438}
439
440
441const char *
442debug_dump_flags(const struct debug_named_value *names,
443                 unsigned long value)
444{
445   static char output[4096];
446   static char rest[256];
447   int first = 1;
448
449   output[0] = '\0';
450
451   while(names->name) {
452      if((names->value & value) == names->value) {
453	 if (!first)
454	    util_strncat(output, "|", sizeof(output));
455	 else
456	    first = 0;
457	 util_strncat(output, names->name, sizeof(output));
458	 value &= ~names->value;
459      }
460      ++names;
461   }
462
463   if (value) {
464      if (!first)
465	 util_strncat(output, "|", sizeof(output));
466      else
467	 first = 0;
468
469      util_snprintf(rest, sizeof(rest), "0x%08lx", value);
470      util_strncat(output, rest, sizeof(output));
471   }
472
473   if(first)
474      return "0";
475
476   return output;
477}
478
479
480static const struct debug_named_value pipe_format_names[] = {
481#ifdef DEBUG
482   DEBUG_NAMED_VALUE(PIPE_FORMAT_NONE),
483   DEBUG_NAMED_VALUE(PIPE_FORMAT_A8R8G8B8_UNORM),
484   DEBUG_NAMED_VALUE(PIPE_FORMAT_X8R8G8B8_UNORM),
485   DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8A8_UNORM),
486   DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8X8_UNORM),
487   DEBUG_NAMED_VALUE(PIPE_FORMAT_A1R5G5B5_UNORM),
488   DEBUG_NAMED_VALUE(PIPE_FORMAT_A4R4G4B4_UNORM),
489   DEBUG_NAMED_VALUE(PIPE_FORMAT_R5G6B5_UNORM),
490   DEBUG_NAMED_VALUE(PIPE_FORMAT_A2B10G10R10_UNORM),
491   DEBUG_NAMED_VALUE(PIPE_FORMAT_L8_UNORM),
492   DEBUG_NAMED_VALUE(PIPE_FORMAT_A8_UNORM),
493   DEBUG_NAMED_VALUE(PIPE_FORMAT_I8_UNORM),
494   DEBUG_NAMED_VALUE(PIPE_FORMAT_A8L8_UNORM),
495   DEBUG_NAMED_VALUE(PIPE_FORMAT_L16_UNORM),
496   DEBUG_NAMED_VALUE(PIPE_FORMAT_YCBCR),
497   DEBUG_NAMED_VALUE(PIPE_FORMAT_YCBCR_REV),
498   DEBUG_NAMED_VALUE(PIPE_FORMAT_Z16_UNORM),
499   DEBUG_NAMED_VALUE(PIPE_FORMAT_Z32_UNORM),
500   DEBUG_NAMED_VALUE(PIPE_FORMAT_Z32_FLOAT),
501   DEBUG_NAMED_VALUE(PIPE_FORMAT_S8Z24_UNORM),
502   DEBUG_NAMED_VALUE(PIPE_FORMAT_Z24S8_UNORM),
503   DEBUG_NAMED_VALUE(PIPE_FORMAT_X8Z24_UNORM),
504   DEBUG_NAMED_VALUE(PIPE_FORMAT_Z24X8_UNORM),
505   DEBUG_NAMED_VALUE(PIPE_FORMAT_S8_UNORM),
506   DEBUG_NAMED_VALUE(PIPE_FORMAT_R64_FLOAT),
507   DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64_FLOAT),
508   DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64B64_FLOAT),
509   DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64B64A64_FLOAT),
510   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_FLOAT),
511   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_FLOAT),
512   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_FLOAT),
513   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_FLOAT),
514   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_UNORM),
515   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_UNORM),
516   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_UNORM),
517   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_UNORM),
518   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_USCALED),
519   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_USCALED),
520   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_USCALED),
521   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_USCALED),
522   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_SNORM),
523   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_SNORM),
524   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_SNORM),
525   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_SNORM),
526   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_SSCALED),
527   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_SSCALED),
528   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_SSCALED),
529   DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_SSCALED),
530   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_UNORM),
531   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_UNORM),
532   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_UNORM),
533   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_UNORM),
534   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_USCALED),
535   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_USCALED),
536   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_USCALED),
537   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_USCALED),
538   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_SNORM),
539   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_SNORM),
540   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_SNORM),
541   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_SNORM),
542   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_SSCALED),
543   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_SSCALED),
544   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_SSCALED),
545   DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_SSCALED),
546   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_UNORM),
547   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_UNORM),
548   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_UNORM),
549   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_UNORM),
550   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_UNORM),
551   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_USCALED),
552   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_USCALED),
553   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_USCALED),
554   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_USCALED),
555   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_USCALED),
556   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_SNORM),
557   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_SNORM),
558   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SNORM),
559   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SNORM),
560   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SNORM),
561   DEBUG_NAMED_VALUE(PIPE_FORMAT_B6G5R5_SNORM),
562   DEBUG_NAMED_VALUE(PIPE_FORMAT_A8B8G8R8_SNORM),
563   DEBUG_NAMED_VALUE(PIPE_FORMAT_X8B8G8R8_SNORM),
564   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_SSCALED),
565   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_SSCALED),
566   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SSCALED),
567   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SSCALED),
568   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SSCALED),
569   DEBUG_NAMED_VALUE(PIPE_FORMAT_L8_SRGB),
570   DEBUG_NAMED_VALUE(PIPE_FORMAT_A8L8_SRGB),
571   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SRGB),
572   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SRGB),
573   DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SRGB),
574   DEBUG_NAMED_VALUE(PIPE_FORMAT_A8R8G8B8_SRGB),
575   DEBUG_NAMED_VALUE(PIPE_FORMAT_X8R8G8B8_SRGB),
576   DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8A8_SRGB),
577   DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8X8_SRGB),
578   DEBUG_NAMED_VALUE(PIPE_FORMAT_X8UB8UG8SR8S_NORM),
579   DEBUG_NAMED_VALUE(PIPE_FORMAT_B6UG5SR5S_NORM),
580   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_RGB),
581   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_RGBA),
582   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT3_RGBA),
583   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT5_RGBA),
584   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_SRGB),
585   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_SRGBA),
586   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT3_SRGBA),
587   DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT5_SRGBA),
588#endif
589   DEBUG_NAMED_VALUE_END
590};
591
592#ifdef DEBUG
593void debug_print_format(const char *msg, unsigned fmt )
594{
595   debug_printf("%s: %s\n", msg, debug_dump_enum(pipe_format_names, fmt));
596}
597#endif
598
599const char *pf_name( enum pipe_format format )
600{
601   return debug_dump_enum(pipe_format_names, format);
602}
603
604
605#ifdef DEBUG
606void debug_dump_image(const char *prefix,
607                      unsigned format, unsigned cpp,
608                      unsigned width, unsigned height,
609                      unsigned stride,
610                      const void *data)
611{
612#ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
613   static unsigned no = 0;
614   char filename[256];
615   WCHAR wfilename[sizeof(filename)];
616   ULONG_PTR iFile = 0;
617   struct {
618      unsigned format;
619      unsigned cpp;
620      unsigned width;
621      unsigned height;
622   } header;
623   unsigned char *pMap = NULL;
624   unsigned i;
625
626   util_snprintf(filename, sizeof(filename), "\\??\\c:\\%03u%s.raw", ++no, prefix);
627   for(i = 0; i < sizeof(filename); ++i)
628      wfilename[i] = (WCHAR)filename[i];
629
630   pMap = (unsigned char *)EngMapFile(wfilename, sizeof(header) + height*width*cpp, &iFile);
631   if(!pMap)
632      return;
633
634   header.format = format;
635   header.cpp = cpp;
636   header.width = width;
637   header.height = height;
638   memcpy(pMap, &header, sizeof(header));
639   pMap += sizeof(header);
640
641   for(i = 0; i < height; ++i) {
642      memcpy(pMap, (unsigned char *)data + stride*i, cpp*width);
643      pMap += cpp*width;
644   }
645
646   EngUnmapFile(iFile);
647#endif
648}
649
650void debug_dump_surface(const char *prefix,
651                        struct pipe_surface *surface)
652{
653   struct pipe_texture *texture;
654   struct pipe_screen *screen;
655   struct pipe_transfer *transfer;
656   void *data;
657
658   if (!surface)
659      return;
660
661   texture = surface->texture;
662   screen = texture->screen;
663
664   transfer = screen->get_tex_transfer(screen, texture, surface->face,
665                                       surface->level, surface->zslice,
666                                       PIPE_TRANSFER_READ, 0, 0, surface->width,
667                                       surface->height);
668
669   data = screen->transfer_map(screen, transfer);
670   if(!data)
671      goto error;
672
673   debug_dump_image(prefix,
674                    transfer->format,
675                    transfer->block.size,
676                    transfer->nblocksx,
677                    transfer->nblocksy,
678                    transfer->stride,
679                    data);
680
681   screen->transfer_unmap(screen, transfer);
682error:
683   screen->tex_transfer_destroy(transfer);
684}
685
686
687#pragma pack(push,2)
688struct bmp_file_header {
689   uint16_t bfType;
690   uint32_t bfSize;
691   uint16_t bfReserved1;
692   uint16_t bfReserved2;
693   uint32_t bfOffBits;
694};
695#pragma pack(pop)
696
697struct bmp_info_header {
698   uint32_t biSize;
699   int32_t biWidth;
700   int32_t biHeight;
701   uint16_t biPlanes;
702   uint16_t biBitCount;
703   uint32_t biCompression;
704   uint32_t biSizeImage;
705   int32_t biXPelsPerMeter;
706   int32_t biYPelsPerMeter;
707   uint32_t biClrUsed;
708   uint32_t biClrImportant;
709};
710
711struct bmp_rgb_quad {
712   uint8_t rgbBlue;
713   uint8_t rgbGreen;
714   uint8_t rgbRed;
715   uint8_t rgbAlpha;
716};
717
718void
719debug_dump_surface_bmp(const char *filename,
720                       struct pipe_surface *surface)
721{
722   struct pipe_transfer *transfer;
723   struct pipe_texture *texture;
724   struct pipe_screen *screen;
725
726   transfer = screen->get_tex_transfer(screen, texture, surface->face,
727                                       surface->level, surface->zslice,
728                                       PIPE_TRANSFER_READ, 0, 0, surface->width,
729                                       surface->height);
730
731   debug_dump_transfer_bmp(filename, transfer);
732
733   screen->tex_transfer_destroy(transfer);
734}
735
736void
737debug_dump_transfer_bmp(const char *filename,
738                        struct pipe_transfer *transfer)
739{
740#ifndef PIPE_SUBSYSTEM_WINDOWS_MINIPORT
741   struct util_stream *stream;
742   struct bmp_file_header bmfh;
743   struct bmp_info_header bmih;
744   float *rgba;
745   unsigned x, y;
746
747   if (!transfer)
748      goto error1;
749
750   rgba = MALLOC(transfer->width*transfer->height*4*sizeof(float));
751   if(!rgba)
752      goto error1;
753
754   bmfh.bfType = 0x4d42;
755   bmfh.bfSize = 14 + 40 + transfer->height*transfer->width*4;
756   bmfh.bfReserved1 = 0;
757   bmfh.bfReserved2 = 0;
758   bmfh.bfOffBits = 14 + 40;
759
760   bmih.biSize = 40;
761   bmih.biWidth = transfer->width;
762   bmih.biHeight = transfer->height;
763   bmih.biPlanes = 1;
764   bmih.biBitCount = 32;
765   bmih.biCompression = 0;
766   bmih.biSizeImage = transfer->height*transfer->width*4;
767   bmih.biXPelsPerMeter = 0;
768   bmih.biYPelsPerMeter = 0;
769   bmih.biClrUsed = 0;
770   bmih.biClrImportant = 0;
771
772   stream = util_stream_create(filename, bmfh.bfSize);
773   if(!stream)
774      goto error2;
775
776   util_stream_write(stream, &bmfh, 14);
777   util_stream_write(stream, &bmih, 40);
778
779   pipe_get_tile_rgba(transfer, 0, 0,
780                      transfer->width, transfer->height,
781                      rgba);
782
783   y = transfer->height;
784   while(y--) {
785      float *ptr = rgba + (transfer->width * y * 4);
786      for(x = 0; x < transfer->width; ++x)
787      {
788         struct bmp_rgb_quad pixel;
789         pixel.rgbRed   = float_to_ubyte(ptr[x*4 + 0]);
790         pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
791         pixel.rgbBlue  = float_to_ubyte(ptr[x*4 + 2]);
792         pixel.rgbAlpha = 255;
793         util_stream_write(stream, &pixel, 4);
794      }
795   }
796
797   util_stream_close(stream);
798error2:
799   FREE(rgba);
800error1:
801   ;
802#endif
803}
804
805#endif
806