gallium: fix refcount bug introduced in eb20e2984
[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 #ifdef DEBUG
105 vfprintf(stderr, format, ap);
106 #endif
107 #endif
108 }
109
110
111 #ifdef DEBUG
112 void debug_print_blob( const char *name,
113 const void *blob,
114 unsigned size )
115 {
116 const unsigned *ublob = (const unsigned *)blob;
117 unsigned i;
118
119 debug_printf("%s (%d dwords%s)\n", name, size/4,
120 size%4 ? "... plus a few bytes" : "");
121
122 for (i = 0; i < size/4; i++) {
123 debug_printf("%d:\t%08x\n", i, ublob[i]);
124 }
125 }
126 #endif
127
128
129 void _debug_break(void)
130 {
131 #if defined(PIPE_ARCH_X86) && defined(PIPE_CC_GCC)
132 __asm("int3");
133 #elif defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)
134 _asm {int 3};
135 #elif defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
136 EngDebugBreak();
137 #else
138 abort();
139 #endif
140 }
141
142
143 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
144 static const char *
145 find(const char *start, const char *end, char c)
146 {
147 const char *p;
148 for(p = start; !end || p != end; ++p) {
149 if(*p == c)
150 return p;
151 if(*p < 32)
152 break;
153 }
154 return NULL;
155 }
156
157 static int
158 compare(const char *start, const char *end, const char *s)
159 {
160 const char *p, *q;
161 for(p = start, q = s; p != end && *q != '\0'; ++p, ++q) {
162 if(*p != *q)
163 return 0;
164 }
165 return p == end && *q == '\0';
166 }
167
168 static void
169 copy(char *dst, const char *start, const char *end, size_t n)
170 {
171 const char *p;
172 char *q;
173 for(p = start, q = dst, n = n - 1; p != end && n; ++p, ++q, --n)
174 *q = *p;
175 *q = '\0';
176 }
177 #endif
178
179
180 static INLINE const char *
181 _debug_get_option(const char *name)
182 {
183 #if defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
184 /* EngMapFile creates the file if it does not exists, so it must either be
185 * disabled on release versions (or put in a less conspicuous place). */
186 #ifdef DEBUG
187 const char *result = NULL;
188 ULONG_PTR iFile = 0;
189 const void *pMap = NULL;
190 const char *sol, *eol, *sep;
191 static char output[1024];
192
193 pMap = EngMapFile(L"\\??\\c:\\gallium.cfg", 0, &iFile);
194 if(pMap) {
195 sol = (const char *)pMap;
196 while(1) {
197 /* TODO: handle LF line endings */
198 eol = find(sol, NULL, '\r');
199 if(!eol || eol == sol)
200 break;
201 sep = find(sol, eol, '=');
202 if(!sep)
203 break;
204 if(compare(sol, sep, name)) {
205 copy(output, sep + 1, eol, sizeof(output));
206 result = output;
207 break;
208 }
209 sol = eol + 2;
210 }
211 EngUnmapFile(iFile);
212 }
213 return result;
214 #else
215 return NULL;
216 #endif
217 #elif defined(PIPE_SUBSYSTEM_WINDOWS_CE) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)
218 /* TODO: implement */
219 return NULL;
220 #else
221 return getenv(name);
222 #endif
223 }
224
225 const char *
226 debug_get_option(const char *name, const char *dfault)
227 {
228 const char *result;
229
230 result = _debug_get_option(name);
231 if(!result)
232 result = dfault;
233
234 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
235
236 return result;
237 }
238
239 boolean
240 debug_get_bool_option(const char *name, boolean dfault)
241 {
242 const char *str = _debug_get_option(name);
243 boolean result;
244
245 if(str == NULL)
246 result = dfault;
247 else if(!util_strcmp(str, "n"))
248 result = FALSE;
249 else if(!util_strcmp(str, "no"))
250 result = FALSE;
251 else if(!util_strcmp(str, "0"))
252 result = FALSE;
253 else if(!util_strcmp(str, "f"))
254 result = FALSE;
255 else if(!util_strcmp(str, "false"))
256 result = FALSE;
257 else
258 result = TRUE;
259
260 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
261
262 return result;
263 }
264
265
266 long
267 debug_get_num_option(const char *name, long dfault)
268 {
269 long result;
270 const char *str;
271
272 str = _debug_get_option(name);
273 if(!str)
274 result = dfault;
275 else {
276 long sign;
277 char c;
278 c = *str++;
279 if(c == '-') {
280 sign = -1;
281 c = *str++;
282 }
283 else {
284 sign = 1;
285 }
286 result = 0;
287 while('0' <= c && c <= '9') {
288 result = result*10 + (c - '0');
289 c = *str++;
290 }
291 result *= sign;
292 }
293
294 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
295
296 return result;
297 }
298
299
300 unsigned long
301 debug_get_flags_option(const char *name,
302 const struct debug_named_value *flags,
303 unsigned long dfault)
304 {
305 unsigned long result;
306 const char *str;
307
308 str = _debug_get_option(name);
309 if(!str)
310 result = dfault;
311 else {
312 result = 0;
313 while( flags->name ) {
314 if (!util_strcmp(str, "all") || util_strstr(str, flags->name ))
315 result |= flags->value;
316 ++flags;
317 }
318 }
319
320 debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
321
322 return result;
323 }
324
325
326 void _debug_assert_fail(const char *expr,
327 const char *file,
328 unsigned line,
329 const char *function)
330 {
331 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
332 #if defined(PIPE_OS_WINDOWS) && !defined(PIPE_SUBSYSTEM_WINDOWS_USER)
333 if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", FALSE))
334 #else
335 if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", TRUE))
336 #endif
337 debug_break();
338 else
339 _debug_printf("continuing...\n");
340 }
341
342
343 const char *
344 debug_dump_enum(const struct debug_named_value *names,
345 unsigned long value)
346 {
347 static char rest[64];
348
349 while(names->name) {
350 if(names->value == value)
351 return names->name;
352 ++names;
353 }
354
355 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
356 return rest;
357 }
358
359
360 const char *
361 debug_dump_flags(const struct debug_named_value *names,
362 unsigned long value)
363 {
364 static char output[4096];
365 static char rest[256];
366 int first = 1;
367
368 output[0] = '\0';
369
370 while(names->name) {
371 if((names->value & value) == names->value) {
372 if (!first)
373 util_strncat(output, "|", sizeof(output));
374 else
375 first = 0;
376 util_strncat(output, names->name, sizeof(output));
377 value &= ~names->value;
378 }
379 ++names;
380 }
381
382 if (value) {
383 if (!first)
384 util_strncat(output, "|", sizeof(output));
385 else
386 first = 0;
387
388 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
389 util_strncat(output, rest, sizeof(output));
390 }
391
392 if(first)
393 return "0";
394
395 return output;
396 }
397
398
399 static const struct debug_named_value pipe_format_names[] = {
400 #ifdef DEBUG
401 DEBUG_NAMED_VALUE(PIPE_FORMAT_NONE),
402 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8R8G8B8_UNORM),
403 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8R8G8B8_UNORM),
404 DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8A8_UNORM),
405 DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8X8_UNORM),
406 DEBUG_NAMED_VALUE(PIPE_FORMAT_A1R5G5B5_UNORM),
407 DEBUG_NAMED_VALUE(PIPE_FORMAT_A4R4G4B4_UNORM),
408 DEBUG_NAMED_VALUE(PIPE_FORMAT_R5G6B5_UNORM),
409 DEBUG_NAMED_VALUE(PIPE_FORMAT_A2B10G10R10_UNORM),
410 DEBUG_NAMED_VALUE(PIPE_FORMAT_L8_UNORM),
411 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8_UNORM),
412 DEBUG_NAMED_VALUE(PIPE_FORMAT_I8_UNORM),
413 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8L8_UNORM),
414 DEBUG_NAMED_VALUE(PIPE_FORMAT_L16_UNORM),
415 DEBUG_NAMED_VALUE(PIPE_FORMAT_YCBCR),
416 DEBUG_NAMED_VALUE(PIPE_FORMAT_YCBCR_REV),
417 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z16_UNORM),
418 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z32_UNORM),
419 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z32_FLOAT),
420 DEBUG_NAMED_VALUE(PIPE_FORMAT_S8Z24_UNORM),
421 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z24S8_UNORM),
422 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8Z24_UNORM),
423 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z24X8_UNORM),
424 DEBUG_NAMED_VALUE(PIPE_FORMAT_S8_UNORM),
425 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64_FLOAT),
426 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64_FLOAT),
427 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64B64_FLOAT),
428 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64B64A64_FLOAT),
429 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_FLOAT),
430 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_FLOAT),
431 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_FLOAT),
432 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_FLOAT),
433 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_UNORM),
434 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_UNORM),
435 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_UNORM),
436 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_UNORM),
437 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_USCALED),
438 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_USCALED),
439 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_USCALED),
440 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_USCALED),
441 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_SNORM),
442 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_SNORM),
443 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_SNORM),
444 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_SNORM),
445 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_SSCALED),
446 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_SSCALED),
447 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_SSCALED),
448 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_SSCALED),
449 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_UNORM),
450 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_UNORM),
451 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_UNORM),
452 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_UNORM),
453 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_USCALED),
454 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_USCALED),
455 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_USCALED),
456 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_USCALED),
457 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_SNORM),
458 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_SNORM),
459 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_SNORM),
460 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_SNORM),
461 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_SSCALED),
462 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_SSCALED),
463 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_SSCALED),
464 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_SSCALED),
465 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_UNORM),
466 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_UNORM),
467 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_UNORM),
468 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_UNORM),
469 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_UNORM),
470 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_USCALED),
471 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_USCALED),
472 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_USCALED),
473 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_USCALED),
474 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_USCALED),
475 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_SNORM),
476 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_SNORM),
477 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SNORM),
478 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SNORM),
479 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SNORM),
480 DEBUG_NAMED_VALUE(PIPE_FORMAT_B6G5R5_SNORM),
481 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8B8G8R8_SNORM),
482 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8B8G8R8_SNORM),
483 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_SSCALED),
484 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_SSCALED),
485 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SSCALED),
486 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SSCALED),
487 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SSCALED),
488 DEBUG_NAMED_VALUE(PIPE_FORMAT_L8_SRGB),
489 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8_L8_SRGB),
490 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SRGB),
491 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SRGB),
492 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SRGB),
493 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8UB8UG8SR8S_NORM),
494 DEBUG_NAMED_VALUE(PIPE_FORMAT_B6UG5SR5S_NORM),
495 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_RGB),
496 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_RGBA),
497 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT3_RGBA),
498 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT5_RGBA),
499 #endif
500 DEBUG_NAMED_VALUE_END
501 };
502
503 #ifdef DEBUG
504 void debug_print_format(const char *msg, unsigned fmt )
505 {
506 debug_printf("%s: %s\n", msg, debug_dump_enum(pipe_format_names, fmt));
507 }
508 #endif
509
510 const char *pf_name( enum pipe_format format )
511 {
512 return debug_dump_enum(pipe_format_names, format);
513 }
514
515
516 #ifdef DEBUG
517 void debug_dump_image(const char *prefix,
518 unsigned format, unsigned cpp,
519 unsigned width, unsigned height,
520 unsigned stride,
521 const void *data)
522 {
523 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
524 static unsigned no = 0;
525 char filename[256];
526 WCHAR wfilename[sizeof(filename)];
527 ULONG_PTR iFile = 0;
528 struct {
529 unsigned format;
530 unsigned cpp;
531 unsigned width;
532 unsigned height;
533 } header;
534 unsigned char *pMap = NULL;
535 unsigned i;
536
537 util_snprintf(filename, sizeof(filename), "\\??\\c:\\%03u%s.raw", ++no, prefix);
538 for(i = 0; i < sizeof(filename); ++i)
539 wfilename[i] = (WCHAR)filename[i];
540
541 pMap = (unsigned char *)EngMapFile(wfilename, sizeof(header) + height*width*cpp, &iFile);
542 if(!pMap)
543 return;
544
545 header.format = format;
546 header.cpp = cpp;
547 header.width = width;
548 header.height = height;
549 memcpy(pMap, &header, sizeof(header));
550 pMap += sizeof(header);
551
552 for(i = 0; i < height; ++i) {
553 memcpy(pMap, (unsigned char *)data + stride*i, cpp*width);
554 pMap += cpp*width;
555 }
556
557 EngUnmapFile(iFile);
558 #endif
559 }
560
561 void debug_dump_surface(const char *prefix,
562 struct pipe_surface *surface)
563 {
564 unsigned surface_usage;
565 void *data;
566
567 if (!surface)
568 goto error1;
569
570 /* XXX: force mappable surface */
571 surface_usage = surface->usage;
572 surface->usage |= PIPE_BUFFER_USAGE_CPU_READ;
573
574 data = pipe_surface_map(surface,
575 PIPE_BUFFER_USAGE_CPU_READ);
576 if(!data)
577 goto error2;
578
579 debug_dump_image(prefix,
580 surface->format,
581 surface->block.size,
582 surface->nblocksx,
583 surface->nblocksy,
584 surface->stride,
585 data);
586
587 pipe_surface_unmap(surface);
588 error2:
589 surface->usage = surface_usage;
590 error1:
591 ;
592 }
593
594
595 #pragma pack(push,2)
596 struct bmp_file_header {
597 uint16_t bfType;
598 uint32_t bfSize;
599 uint16_t bfReserved1;
600 uint16_t bfReserved2;
601 uint32_t bfOffBits;
602 };
603 #pragma pack(pop)
604
605 struct bmp_info_header {
606 uint32_t biSize;
607 int32_t biWidth;
608 int32_t biHeight;
609 uint16_t biPlanes;
610 uint16_t biBitCount;
611 uint32_t biCompression;
612 uint32_t biSizeImage;
613 int32_t biXPelsPerMeter;
614 int32_t biYPelsPerMeter;
615 uint32_t biClrUsed;
616 uint32_t biClrImportant;
617 };
618
619 struct bmp_rgb_quad {
620 uint8_t rgbBlue;
621 uint8_t rgbGreen;
622 uint8_t rgbRed;
623 uint8_t rgbAlpha;
624 };
625
626 void
627 debug_dump_surface_bmp(const char *filename,
628 struct pipe_surface *surface)
629 {
630 struct util_stream *stream;
631 unsigned surface_usage;
632 struct bmp_file_header bmfh;
633 struct bmp_info_header bmih;
634 float *rgba;
635 unsigned x, y;
636
637 if (!surface)
638 goto error1;
639
640 rgba = MALLOC(surface->width*4*sizeof(float));
641 if(!rgba)
642 goto error1;
643
644 bmfh.bfType = 0x4d42;
645 bmfh.bfSize = 14 + 40 + surface->height*surface->width*4;
646 bmfh.bfReserved1 = 0;
647 bmfh.bfReserved2 = 0;
648 bmfh.bfOffBits = 14 + 40;
649
650 bmih.biSize = 40;
651 bmih.biWidth = surface->width;
652 bmih.biHeight = surface->height;
653 bmih.biPlanes = 1;
654 bmih.biBitCount = 32;
655 bmih.biCompression = 0;
656 bmih.biSizeImage = surface->height*surface->width*4;
657 bmih.biXPelsPerMeter = 0;
658 bmih.biYPelsPerMeter = 0;
659 bmih.biClrUsed = 0;
660 bmih.biClrImportant = 0;
661
662 stream = util_stream_create(filename, bmfh.bfSize);
663 if(!stream)
664 goto error2;
665
666 util_stream_write(stream, &bmfh, 14);
667 util_stream_write(stream, &bmih, 40);
668
669 /* XXX: force mappable surface */
670 surface_usage = surface->usage;
671 surface->usage |= PIPE_BUFFER_USAGE_CPU_READ;
672
673 y = surface->height;
674 while(y--) {
675 pipe_get_tile_rgba(surface,
676 0, y, surface->width, 1,
677 rgba);
678 for(x = 0; x < surface->width; ++x)
679 {
680 struct bmp_rgb_quad pixel;
681 pixel.rgbRed = float_to_ubyte(rgba[x*4 + 0]);
682 pixel.rgbGreen = float_to_ubyte(rgba[x*4 + 1]);
683 pixel.rgbBlue = float_to_ubyte(rgba[x*4 + 2]);
684 pixel.rgbAlpha = float_to_ubyte(rgba[x*4 + 3]);
685 util_stream_write(stream, &pixel, 4);
686 }
687 }
688
689 surface->usage = surface_usage;
690
691 util_stream_close(stream);
692 error2:
693 FREE(rgba);
694 error1:
695 ;
696 }
697
698 #endif