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