util: move pipe_prim_names array into u_prim_name()
[mesa.git] / src / gallium / auxiliary / util / u_debug.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
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 VMWARE 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 "pipe/p_compiler.h"
33 #include "util/u_debug.h"
34 #include "pipe/p_format.h"
35 #include "pipe/p_state.h"
36 #include "util/u_inlines.h"
37 #include "util/u_format.h"
38 #include "util/u_memory.h"
39 #include "util/u_string.h"
40 #include "util/u_math.h"
41 #include "util/u_tile.h"
42 #include "util/u_prim.h"
43 #include "util/u_surface.h"
44
45 #include <stdio.h>
46 #include <limits.h> /* CHAR_BIT */
47 #include <ctype.h> /* isalnum */
48
49 #ifdef _WIN32
50 #include <windows.h>
51 #include <stdlib.h>
52 #endif
53
54
55 void _debug_vprintf(const char *format, va_list ap)
56 {
57 static char buf[4096] = {'\0'};
58 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
59 /* We buffer until we find a newline. */
60 size_t len = strlen(buf);
61 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
62 if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
63 os_log_message(buf);
64 buf[0] = '\0';
65 }
66 #else
67 util_vsnprintf(buf, sizeof(buf), format, ap);
68 os_log_message(buf);
69 #endif
70 }
71
72
73 void
74 debug_disable_error_message_boxes(void)
75 {
76 #ifdef _WIN32
77 /* When Windows' error message boxes are disabled for this process (as is
78 * typically the case when running tests in an automated fashion) we disable
79 * CRT message boxes too.
80 */
81 UINT uMode = SetErrorMode(0);
82 SetErrorMode(uMode);
83 if (uMode & SEM_FAILCRITICALERRORS) {
84 /* Disable assertion failure message box.
85 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
86 */
87 _set_error_mode(_OUT_TO_STDERR);
88 #ifdef _MSC_VER
89 /* Disable abort message box.
90 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
91 */
92 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
93 #endif
94 }
95 #endif /* _WIN32 */
96 }
97
98
99 #ifdef DEBUG
100 void debug_print_blob( const char *name,
101 const void *blob,
102 unsigned size )
103 {
104 const unsigned *ublob = (const unsigned *)blob;
105 unsigned i;
106
107 debug_printf("%s (%d dwords%s)\n", name, size/4,
108 size%4 ? "... plus a few bytes" : "");
109
110 for (i = 0; i < size/4; i++) {
111 debug_printf("%d:\t%08x\n", i, ublob[i]);
112 }
113 }
114 #endif
115
116
117 static boolean
118 debug_get_option_should_print(void)
119 {
120 static boolean first = TRUE;
121 static boolean value = FALSE;
122
123 if (!first)
124 return value;
125
126 /* Oh hey this will call into this function,
127 * but its cool since we set first to false
128 */
129 first = FALSE;
130 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
131 /* XXX should we print this option? Currently it wont */
132 return value;
133 }
134
135 const char *
136 debug_get_option(const char *name, const char *dfault)
137 {
138 const char *result;
139
140 result = os_get_option(name);
141 if(!result)
142 result = dfault;
143
144 if (debug_get_option_should_print())
145 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
146
147 return result;
148 }
149
150 boolean
151 debug_get_bool_option(const char *name, boolean dfault)
152 {
153 const char *str = os_get_option(name);
154 boolean result;
155
156 if(str == NULL)
157 result = dfault;
158 else if(!util_strcmp(str, "n"))
159 result = FALSE;
160 else if(!util_strcmp(str, "no"))
161 result = FALSE;
162 else if(!util_strcmp(str, "0"))
163 result = FALSE;
164 else if(!util_strcmp(str, "f"))
165 result = FALSE;
166 else if(!util_strcmp(str, "F"))
167 result = FALSE;
168 else if(!util_strcmp(str, "false"))
169 result = FALSE;
170 else if(!util_strcmp(str, "FALSE"))
171 result = FALSE;
172 else
173 result = TRUE;
174
175 if (debug_get_option_should_print())
176 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
177
178 return result;
179 }
180
181
182 long
183 debug_get_num_option(const char *name, long dfault)
184 {
185 long result;
186 const char *str;
187
188 str = os_get_option(name);
189 if(!str)
190 result = dfault;
191 else {
192 long sign;
193 char c;
194 c = *str++;
195 if(c == '-') {
196 sign = -1;
197 c = *str++;
198 }
199 else {
200 sign = 1;
201 }
202 result = 0;
203 while('0' <= c && c <= '9') {
204 result = result*10 + (c - '0');
205 c = *str++;
206 }
207 result *= sign;
208 }
209
210 if (debug_get_option_should_print())
211 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
212
213 return result;
214 }
215
216 static boolean str_has_option(const char *str, const char *name)
217 {
218 /* Empty string. */
219 if (!*str) {
220 return FALSE;
221 }
222
223 /* OPTION=all */
224 if (!util_strcmp(str, "all")) {
225 return TRUE;
226 }
227
228 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
229 {
230 const char *start = str;
231 unsigned name_len = strlen(name);
232
233 /* 'start' is the beginning of the currently-parsed word,
234 * we increment 'str' each iteration.
235 * if we find either the end of string or a non-alphanumeric character,
236 * we compare 'start' up to 'str-1' with 'name'. */
237
238 while (1) {
239 if (!*str || !(isalnum(*str) || *str == '_')) {
240 if (str-start == name_len &&
241 !memcmp(start, name, name_len)) {
242 return TRUE;
243 }
244
245 if (!*str) {
246 return FALSE;
247 }
248
249 start = str+1;
250 }
251
252 str++;
253 }
254 }
255
256 return FALSE;
257 }
258
259 unsigned long
260 debug_get_flags_option(const char *name,
261 const struct debug_named_value *flags,
262 unsigned long dfault)
263 {
264 unsigned long result;
265 const char *str;
266 const struct debug_named_value *orig = flags;
267 unsigned namealign = 0;
268
269 str = os_get_option(name);
270 if(!str)
271 result = dfault;
272 else if (!util_strcmp(str, "help")) {
273 result = dfault;
274 _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
275 for (; flags->name; ++flags)
276 namealign = MAX2(namealign, strlen(flags->name));
277 for (flags = orig; flags->name; ++flags)
278 _debug_printf("| %*s [0x%0*lx]%s%s\n", namealign, flags->name,
279 (int)sizeof(unsigned long)*CHAR_BIT/4, flags->value,
280 flags->desc ? " " : "", flags->desc ? flags->desc : "");
281 }
282 else {
283 result = 0;
284 while( flags->name ) {
285 if (str_has_option(str, flags->name))
286 result |= flags->value;
287 ++flags;
288 }
289 }
290
291 if (debug_get_option_should_print()) {
292 if (str) {
293 debug_printf("%s: %s = 0x%lx (%s)\n", __FUNCTION__, name, result, str);
294 } else {
295 debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
296 }
297 }
298
299 return result;
300 }
301
302
303 void _debug_assert_fail(const char *expr,
304 const char *file,
305 unsigned line,
306 const char *function)
307 {
308 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
309 os_abort();
310 }
311
312
313 const char *
314 debug_dump_enum(const struct debug_named_value *names,
315 unsigned long value)
316 {
317 static char rest[64];
318
319 while(names->name) {
320 if(names->value == value)
321 return names->name;
322 ++names;
323 }
324
325 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
326 return rest;
327 }
328
329
330 const char *
331 debug_dump_enum_noprefix(const struct debug_named_value *names,
332 const char *prefix,
333 unsigned long value)
334 {
335 static char rest[64];
336
337 while(names->name) {
338 if(names->value == value) {
339 const char *name = names->name;
340 while (*name == *prefix) {
341 name++;
342 prefix++;
343 }
344 return name;
345 }
346 ++names;
347 }
348
349
350
351 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
352 return rest;
353 }
354
355
356 const char *
357 debug_dump_flags(const struct debug_named_value *names,
358 unsigned long value)
359 {
360 static char output[4096];
361 static char rest[256];
362 int first = 1;
363
364 output[0] = '\0';
365
366 while(names->name) {
367 if((names->value & value) == names->value) {
368 if (!first)
369 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
370 else
371 first = 0;
372 util_strncat(output, names->name, sizeof(output) - strlen(output) - 1);
373 output[sizeof(output) - 1] = '\0';
374 value &= ~names->value;
375 }
376 ++names;
377 }
378
379 if (value) {
380 if (!first)
381 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
382 else
383 first = 0;
384
385 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
386 util_strncat(output, rest, sizeof(output) - strlen(output) - 1);
387 output[sizeof(output) - 1] = '\0';
388 }
389
390 if(first)
391 return "0";
392
393 return output;
394 }
395
396
397 #ifdef DEBUG
398 void debug_print_format(const char *msg, unsigned fmt )
399 {
400 debug_printf("%s: %s\n", msg, util_format_name(fmt));
401 }
402 #endif
403
404
405 /** Return string name of given primitive type */
406 const char *
407 u_prim_name(unsigned prim)
408 {
409 static const struct debug_named_value names[] = {
410 DEBUG_NAMED_VALUE(PIPE_PRIM_POINTS),
411 DEBUG_NAMED_VALUE(PIPE_PRIM_LINES),
412 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_LOOP),
413 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP),
414 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES),
415 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP),
416 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_FAN),
417 DEBUG_NAMED_VALUE(PIPE_PRIM_QUADS),
418 DEBUG_NAMED_VALUE(PIPE_PRIM_QUAD_STRIP),
419 DEBUG_NAMED_VALUE(PIPE_PRIM_POLYGON),
420 DEBUG_NAMED_VALUE(PIPE_PRIM_LINES_ADJACENCY),
421 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP_ADJACENCY),
422 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES_ADJACENCY),
423 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY),
424 DEBUG_NAMED_VALUE_END
425 };
426 return debug_dump_enum(names, prim);
427 }
428
429
430
431 #ifdef DEBUG
432 int fl_indent = 0;
433 const char* fl_function[1024];
434
435 int debug_funclog_enter(const char* f, const int line, const char* file)
436 {
437 int i;
438
439 for (i = 0; i < fl_indent; i++)
440 debug_printf(" ");
441 debug_printf("%s\n", f);
442
443 assert(fl_indent < 1023);
444 fl_function[fl_indent++] = f;
445
446 return 0;
447 }
448
449 void debug_funclog_exit(const char* f, const int line, const char* file)
450 {
451 --fl_indent;
452 assert(fl_indent >= 0);
453 assert(fl_function[fl_indent] == f);
454 }
455
456 void debug_funclog_enter_exit(const char* f, const int line, const char* file)
457 {
458 int i;
459 for (i = 0; i < fl_indent; i++)
460 debug_printf(" ");
461 debug_printf("%s\n", f);
462 }
463 #endif
464
465
466
467 #ifdef DEBUG
468 /**
469 * Dump an image to .ppm file.
470 * \param format PIPE_FORMAT_x
471 * \param cpp bytes per pixel
472 * \param width width in pixels
473 * \param height height in pixels
474 * \param stride row stride in bytes
475 */
476 void debug_dump_image(const char *prefix,
477 enum pipe_format format, unsigned cpp,
478 unsigned width, unsigned height,
479 unsigned stride,
480 const void *data)
481 {
482 /* write a ppm file */
483 char filename[256];
484 unsigned char *rgb8;
485 FILE *f;
486
487 util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
488
489 rgb8 = MALLOC(height * width * 3);
490 if (!rgb8) {
491 return;
492 }
493
494 util_format_translate(
495 PIPE_FORMAT_R8G8B8_UNORM,
496 rgb8, width * 3,
497 0, 0,
498 format,
499 data, stride,
500 0, 0, width, height);
501
502 /* Must be opened in binary mode or DOS line ending causes data
503 * to be read with one byte offset.
504 */
505 f = fopen(filename, "wb");
506 if (f) {
507 fprintf(f, "P6\n");
508 fprintf(f, "# ppm-file created by gallium\n");
509 fprintf(f, "%i %i\n", width, height);
510 fprintf(f, "255\n");
511 fwrite(rgb8, 1, height * width * 3, f);
512 fclose(f);
513 }
514 else {
515 fprintf(stderr, "Can't open %s for writing\n", filename);
516 }
517
518 FREE(rgb8);
519 }
520
521 /* FIXME: dump resources, not surfaces... */
522 void debug_dump_surface(struct pipe_context *pipe,
523 const char *prefix,
524 struct pipe_surface *surface)
525 {
526 struct pipe_resource *texture;
527 struct pipe_transfer *transfer;
528 void *data;
529
530 if (!surface)
531 return;
532
533 /* XXX: this doesn't necessarily work, as the driver may be using
534 * temporary storage for the surface which hasn't been propagated
535 * back into the texture. Need to nail down the semantics of views
536 * and transfers a bit better before we can say if extra work needs
537 * to be done here:
538 */
539 texture = surface->texture;
540
541 data = pipe_transfer_map(pipe, texture, surface->u.tex.level,
542 surface->u.tex.first_layer,
543 PIPE_TRANSFER_READ,
544 0, 0, surface->width, surface->height, &transfer);
545 if(!data)
546 return;
547
548 debug_dump_image(prefix,
549 texture->format,
550 util_format_get_blocksize(texture->format),
551 util_format_get_nblocksx(texture->format, surface->width),
552 util_format_get_nblocksy(texture->format, surface->height),
553 transfer->stride,
554 data);
555
556 pipe->transfer_unmap(pipe, transfer);
557 }
558
559
560 void debug_dump_texture(struct pipe_context *pipe,
561 const char *prefix,
562 struct pipe_resource *texture)
563 {
564 struct pipe_surface *surface, surf_tmpl;
565
566 if (!texture)
567 return;
568
569 /* XXX for now, just dump image for layer=0, level=0 */
570 u_surface_default_template(&surf_tmpl, texture);
571 surface = pipe->create_surface(pipe, texture, &surf_tmpl);
572 if (surface) {
573 debug_dump_surface(pipe, prefix, surface);
574 pipe->surface_destroy(pipe, surface);
575 }
576 }
577
578
579 #pragma pack(push,2)
580 struct bmp_file_header {
581 uint16_t bfType;
582 uint32_t bfSize;
583 uint16_t bfReserved1;
584 uint16_t bfReserved2;
585 uint32_t bfOffBits;
586 };
587 #pragma pack(pop)
588
589 struct bmp_info_header {
590 uint32_t biSize;
591 int32_t biWidth;
592 int32_t biHeight;
593 uint16_t biPlanes;
594 uint16_t biBitCount;
595 uint32_t biCompression;
596 uint32_t biSizeImage;
597 int32_t biXPelsPerMeter;
598 int32_t biYPelsPerMeter;
599 uint32_t biClrUsed;
600 uint32_t biClrImportant;
601 };
602
603 struct bmp_rgb_quad {
604 uint8_t rgbBlue;
605 uint8_t rgbGreen;
606 uint8_t rgbRed;
607 uint8_t rgbAlpha;
608 };
609
610 void
611 debug_dump_surface_bmp(struct pipe_context *pipe,
612 const char *filename,
613 struct pipe_surface *surface)
614 {
615 struct pipe_transfer *transfer;
616 struct pipe_resource *texture = surface->texture;
617 void *ptr;
618
619 ptr = pipe_transfer_map(pipe, texture, surface->u.tex.level,
620 surface->u.tex.first_layer, PIPE_TRANSFER_READ,
621 0, 0, surface->width, surface->height, &transfer);
622
623 debug_dump_transfer_bmp(pipe, filename, transfer, ptr);
624
625 pipe->transfer_unmap(pipe, transfer);
626 }
627
628 void
629 debug_dump_transfer_bmp(struct pipe_context *pipe,
630 const char *filename,
631 struct pipe_transfer *transfer, void *ptr)
632 {
633 float *rgba;
634
635 if (!transfer)
636 goto error1;
637
638 rgba = MALLOC(transfer->box.width *
639 transfer->box.height *
640 transfer->box.depth *
641 4*sizeof(float));
642 if(!rgba)
643 goto error1;
644
645 pipe_get_tile_rgba(transfer, ptr, 0, 0,
646 transfer->box.width, transfer->box.height,
647 rgba);
648
649 debug_dump_float_rgba_bmp(filename,
650 transfer->box.width, transfer->box.height,
651 rgba, transfer->box.width);
652
653 FREE(rgba);
654 error1:
655 ;
656 }
657
658 void
659 debug_dump_float_rgba_bmp(const char *filename,
660 unsigned width, unsigned height,
661 float *rgba, unsigned stride)
662 {
663 FILE *stream;
664 struct bmp_file_header bmfh;
665 struct bmp_info_header bmih;
666 unsigned x, y;
667
668 if(!rgba)
669 goto error1;
670
671 bmfh.bfType = 0x4d42;
672 bmfh.bfSize = 14 + 40 + height*width*4;
673 bmfh.bfReserved1 = 0;
674 bmfh.bfReserved2 = 0;
675 bmfh.bfOffBits = 14 + 40;
676
677 bmih.biSize = 40;
678 bmih.biWidth = width;
679 bmih.biHeight = height;
680 bmih.biPlanes = 1;
681 bmih.biBitCount = 32;
682 bmih.biCompression = 0;
683 bmih.biSizeImage = height*width*4;
684 bmih.biXPelsPerMeter = 0;
685 bmih.biYPelsPerMeter = 0;
686 bmih.biClrUsed = 0;
687 bmih.biClrImportant = 0;
688
689 stream = fopen(filename, "wb");
690 if(!stream)
691 goto error1;
692
693 fwrite(&bmfh, 14, 1, stream);
694 fwrite(&bmih, 40, 1, stream);
695
696 y = height;
697 while(y--) {
698 float *ptr = rgba + (stride * y * 4);
699 for(x = 0; x < width; ++x)
700 {
701 struct bmp_rgb_quad pixel;
702 pixel.rgbRed = float_to_ubyte(ptr[x*4 + 0]);
703 pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]);
704 pixel.rgbBlue = float_to_ubyte(ptr[x*4 + 2]);
705 pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]);
706 fwrite(&pixel, 1, 4, stream);
707 }
708 }
709
710 fclose(stream);
711 error1:
712 ;
713 }
714
715
716 /**
717 * Print PIPE_TRANSFER_x flags with a message.
718 */
719 void
720 debug_print_transfer_flags(const char *msg, unsigned usage)
721 {
722 static const struct debug_named_value names[] = {
723 DEBUG_NAMED_VALUE(PIPE_TRANSFER_READ),
724 DEBUG_NAMED_VALUE(PIPE_TRANSFER_WRITE),
725 DEBUG_NAMED_VALUE(PIPE_TRANSFER_MAP_DIRECTLY),
726 DEBUG_NAMED_VALUE(PIPE_TRANSFER_DISCARD_RANGE),
727 DEBUG_NAMED_VALUE(PIPE_TRANSFER_DONTBLOCK),
728 DEBUG_NAMED_VALUE(PIPE_TRANSFER_UNSYNCHRONIZED),
729 DEBUG_NAMED_VALUE(PIPE_TRANSFER_FLUSH_EXPLICIT),
730 DEBUG_NAMED_VALUE(PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE),
731 DEBUG_NAMED_VALUE(PIPE_TRANSFER_PERSISTENT),
732 DEBUG_NAMED_VALUE(PIPE_TRANSFER_COHERENT),
733 DEBUG_NAMED_VALUE_END
734 };
735
736 debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
737 }
738
739
740
741 #endif