gallium/u_dump: add and use util_dump_transfer_usage
[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 "util/u_dump.h"
35 #include "pipe/p_format.h"
36 #include "pipe/p_state.h"
37 #include "util/u_inlines.h"
38 #include "util/u_format.h"
39 #include "util/u_memory.h"
40 #include "util/u_string.h"
41 #include "util/u_math.h"
42 #include "util/u_prim.h"
43 #include <inttypes.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
56 _debug_vprintf(const char *format, va_list ap)
57 {
58 static char buf[4096] = {'\0'};
59 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
60 /* We buffer until we find a newline. */
61 size_t len = strlen(buf);
62 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
63 if (ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
64 os_log_message(buf);
65 buf[0] = '\0';
66 }
67 #else
68 util_vsnprintf(buf, sizeof(buf), format, ap);
69 os_log_message(buf);
70 #endif
71 }
72
73
74 void
75 _pipe_debug_message(struct pipe_debug_callback *cb,
76 unsigned *id,
77 enum pipe_debug_type type,
78 const char *fmt, ...)
79 {
80 va_list args;
81 va_start(args, fmt);
82 if (cb && cb->debug_message)
83 cb->debug_message(cb->data, id, type, fmt, args);
84 va_end(args);
85 }
86
87
88 void
89 debug_disable_error_message_boxes(void)
90 {
91 #ifdef _WIN32
92 /* When Windows' error message boxes are disabled for this process (as is
93 * typically the case when running tests in an automated fashion) we disable
94 * CRT message boxes too.
95 */
96 UINT uMode = SetErrorMode(0);
97 SetErrorMode(uMode);
98 if (uMode & SEM_FAILCRITICALERRORS) {
99 /* Disable assertion failure message box.
100 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
101 */
102 _set_error_mode(_OUT_TO_STDERR);
103 #ifdef _MSC_VER
104 /* Disable abort message box.
105 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
106 */
107 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
108 #endif
109 }
110 #endif /* _WIN32 */
111 }
112
113
114 #ifdef DEBUG
115 void
116 debug_print_blob(const char *name, const void *blob, unsigned size)
117 {
118 const unsigned *ublob = (const unsigned *)blob;
119 unsigned i;
120
121 debug_printf("%s (%d dwords%s)\n", name, size/4,
122 size%4 ? "... plus a few bytes" : "");
123
124 for (i = 0; i < size/4; i++) {
125 debug_printf("%d:\t%08x\n", i, ublob[i]);
126 }
127 }
128 #endif
129
130
131 static boolean
132 debug_get_option_should_print(void)
133 {
134 static boolean first = TRUE;
135 static boolean value = FALSE;
136
137 if (!first)
138 return value;
139
140 /* Oh hey this will call into this function,
141 * but its cool since we set first to false
142 */
143 first = FALSE;
144 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
145 /* XXX should we print this option? Currently it wont */
146 return value;
147 }
148
149
150 const char *
151 debug_get_option(const char *name, const char *dfault)
152 {
153 const char *result;
154
155 result = os_get_option(name);
156 if (!result)
157 result = dfault;
158
159 if (debug_get_option_should_print())
160 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
161 result ? result : "(null)");
162
163 return result;
164 }
165
166
167 boolean
168 debug_get_bool_option(const char *name, boolean dfault)
169 {
170 const char *str = os_get_option(name);
171 boolean result;
172
173 if (str == NULL)
174 result = dfault;
175 else if (!util_strcmp(str, "n"))
176 result = FALSE;
177 else if (!util_strcmp(str, "no"))
178 result = FALSE;
179 else if (!util_strcmp(str, "0"))
180 result = FALSE;
181 else if (!util_strcmp(str, "f"))
182 result = FALSE;
183 else if (!util_strcmp(str, "F"))
184 result = FALSE;
185 else if (!util_strcmp(str, "false"))
186 result = FALSE;
187 else if (!util_strcmp(str, "FALSE"))
188 result = FALSE;
189 else
190 result = TRUE;
191
192 if (debug_get_option_should_print())
193 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
194 result ? "TRUE" : "FALSE");
195
196 return result;
197 }
198
199
200 long
201 debug_get_num_option(const char *name, long dfault)
202 {
203 long result;
204 const char *str;
205
206 str = os_get_option(name);
207 if (!str) {
208 result = dfault;
209 } else {
210 char *endptr;
211
212 result = strtol(str, &endptr, 0);
213 if (str == endptr) {
214 /* Restore the default value when no digits were found. */
215 result = dfault;
216 }
217 }
218
219 if (debug_get_option_should_print())
220 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
221
222 return result;
223 }
224
225
226 static boolean
227 str_has_option(const char *str, const char *name)
228 {
229 /* Empty string. */
230 if (!*str) {
231 return FALSE;
232 }
233
234 /* OPTION=all */
235 if (!util_strcmp(str, "all")) {
236 return TRUE;
237 }
238
239 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
240 {
241 const char *start = str;
242 unsigned name_len = strlen(name);
243
244 /* 'start' is the beginning of the currently-parsed word,
245 * we increment 'str' each iteration.
246 * if we find either the end of string or a non-alphanumeric character,
247 * we compare 'start' up to 'str-1' with 'name'. */
248
249 while (1) {
250 if (!*str || !(isalnum(*str) || *str == '_')) {
251 if (str-start == name_len &&
252 !memcmp(start, name, name_len)) {
253 return TRUE;
254 }
255
256 if (!*str) {
257 return FALSE;
258 }
259
260 start = str+1;
261 }
262
263 str++;
264 }
265 }
266
267 return FALSE;
268 }
269
270
271 uint64_t
272 debug_get_flags_option(const char *name,
273 const struct debug_named_value *flags,
274 uint64_t dfault)
275 {
276 uint64_t result;
277 const char *str;
278 const struct debug_named_value *orig = flags;
279 unsigned namealign = 0;
280
281 str = os_get_option(name);
282 if (!str)
283 result = dfault;
284 else if (!util_strcmp(str, "help")) {
285 result = dfault;
286 _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
287 for (; flags->name; ++flags)
288 namealign = MAX2(namealign, strlen(flags->name));
289 for (flags = orig; flags->name; ++flags)
290 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
291 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
292 flags->desc ? " " : "", flags->desc ? flags->desc : "");
293 }
294 else {
295 result = 0;
296 while (flags->name) {
297 if (str_has_option(str, flags->name))
298 result |= flags->value;
299 ++flags;
300 }
301 }
302
303 if (debug_get_option_should_print()) {
304 if (str) {
305 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n",
306 __FUNCTION__, name, result, str);
307 } else {
308 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
309 }
310 }
311
312 return result;
313 }
314
315
316 void
317 _debug_assert_fail(const char *expr, const char *file, unsigned line,
318 const char *function)
319 {
320 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n",
321 file, line, function, expr);
322 os_abort();
323 }
324
325
326 const char *
327 debug_dump_enum(const struct debug_named_value *names,
328 unsigned long value)
329 {
330 static char rest[64];
331
332 while (names->name) {
333 if (names->value == value)
334 return names->name;
335 ++names;
336 }
337
338 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
339 return rest;
340 }
341
342
343 const char *
344 debug_dump_enum_noprefix(const struct debug_named_value *names,
345 const char *prefix,
346 unsigned long value)
347 {
348 static char rest[64];
349
350 while (names->name) {
351 if (names->value == value) {
352 const char *name = names->name;
353 while (*name == *prefix) {
354 name++;
355 prefix++;
356 }
357 return name;
358 }
359 ++names;
360 }
361
362 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
363 return rest;
364 }
365
366
367 const char *
368 debug_dump_flags(const struct debug_named_value *names, unsigned long value)
369 {
370 static char output[4096];
371 static char rest[256];
372 int first = 1;
373
374 output[0] = '\0';
375
376 while (names->name) {
377 if ((names->value & value) == names->value) {
378 if (!first)
379 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
380 else
381 first = 0;
382 util_strncat(output, names->name, sizeof(output) - strlen(output) - 1);
383 output[sizeof(output) - 1] = '\0';
384 value &= ~names->value;
385 }
386 ++names;
387 }
388
389 if (value) {
390 if (!first)
391 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
392 else
393 first = 0;
394
395 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
396 util_strncat(output, rest, sizeof(output) - strlen(output) - 1);
397 output[sizeof(output) - 1] = '\0';
398 }
399
400 if (first)
401 return "0";
402
403 return output;
404 }
405
406
407 #ifdef DEBUG
408 void
409 debug_print_format(const char *msg, unsigned fmt )
410 {
411 debug_printf("%s: %s\n", msg, util_format_name(fmt));
412 }
413 #endif
414
415
416 /** Return string name of given primitive type */
417 const char *
418 u_prim_name(enum pipe_prim_type prim)
419 {
420 static const struct debug_named_value names[] = {
421 DEBUG_NAMED_VALUE(PIPE_PRIM_POINTS),
422 DEBUG_NAMED_VALUE(PIPE_PRIM_LINES),
423 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_LOOP),
424 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP),
425 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES),
426 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP),
427 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_FAN),
428 DEBUG_NAMED_VALUE(PIPE_PRIM_QUADS),
429 DEBUG_NAMED_VALUE(PIPE_PRIM_QUAD_STRIP),
430 DEBUG_NAMED_VALUE(PIPE_PRIM_POLYGON),
431 DEBUG_NAMED_VALUE(PIPE_PRIM_LINES_ADJACENCY),
432 DEBUG_NAMED_VALUE(PIPE_PRIM_LINE_STRIP_ADJACENCY),
433 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLES_ADJACENCY),
434 DEBUG_NAMED_VALUE(PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY),
435 DEBUG_NAMED_VALUE_END
436 };
437 return debug_dump_enum(names, prim);
438 }
439
440
441
442 #ifdef DEBUG
443 int fl_indent = 0;
444 const char* fl_function[1024];
445
446 int
447 debug_funclog_enter(const char* f, const int line, const char* file)
448 {
449 int i;
450
451 for (i = 0; i < fl_indent; i++)
452 debug_printf(" ");
453 debug_printf("%s\n", f);
454
455 assert(fl_indent < 1023);
456 fl_function[fl_indent++] = f;
457
458 return 0;
459 }
460
461 void
462 debug_funclog_exit(const char* f, const int line, const char* file)
463 {
464 --fl_indent;
465 assert(fl_indent >= 0);
466 assert(fl_function[fl_indent] == f);
467 }
468
469 void
470 debug_funclog_enter_exit(const char* f, const int line, const char* file)
471 {
472 int i;
473 for (i = 0; i < fl_indent; i++)
474 debug_printf(" ");
475 debug_printf("%s\n", f);
476 }
477 #endif
478
479
480
481 #ifdef DEBUG
482 /**
483 * Print PIPE_TRANSFER_x flags with a message.
484 */
485 void
486 debug_print_transfer_flags(const char *msg, unsigned usage)
487 {
488 debug_printf("%s: ", msg);
489 util_dump_transfer_usage(stdout, usage);
490 printf("\n");
491 }
492
493
494 /**
495 * Print PIPE_BIND_x flags with a message.
496 */
497 void
498 debug_print_bind_flags(const char *msg, unsigned usage)
499 {
500 static const struct debug_named_value names[] = {
501 DEBUG_NAMED_VALUE(PIPE_BIND_DEPTH_STENCIL),
502 DEBUG_NAMED_VALUE(PIPE_BIND_RENDER_TARGET),
503 DEBUG_NAMED_VALUE(PIPE_BIND_BLENDABLE),
504 DEBUG_NAMED_VALUE(PIPE_BIND_SAMPLER_VIEW),
505 DEBUG_NAMED_VALUE(PIPE_BIND_VERTEX_BUFFER),
506 DEBUG_NAMED_VALUE(PIPE_BIND_INDEX_BUFFER),
507 DEBUG_NAMED_VALUE(PIPE_BIND_CONSTANT_BUFFER),
508 DEBUG_NAMED_VALUE(PIPE_BIND_DISPLAY_TARGET),
509 DEBUG_NAMED_VALUE(PIPE_BIND_STREAM_OUTPUT),
510 DEBUG_NAMED_VALUE(PIPE_BIND_CURSOR),
511 DEBUG_NAMED_VALUE(PIPE_BIND_CUSTOM),
512 DEBUG_NAMED_VALUE(PIPE_BIND_GLOBAL),
513 DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_BUFFER),
514 DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_IMAGE),
515 DEBUG_NAMED_VALUE(PIPE_BIND_COMPUTE_RESOURCE),
516 DEBUG_NAMED_VALUE(PIPE_BIND_COMMAND_ARGS_BUFFER),
517 DEBUG_NAMED_VALUE(PIPE_BIND_SCANOUT),
518 DEBUG_NAMED_VALUE(PIPE_BIND_SHARED),
519 DEBUG_NAMED_VALUE(PIPE_BIND_LINEAR),
520 DEBUG_NAMED_VALUE_END
521 };
522
523 debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
524 }
525
526
527 /**
528 * Print PIPE_USAGE_x enum values with a message.
529 */
530 void
531 debug_print_usage_enum(const char *msg, enum pipe_resource_usage usage)
532 {
533 static const struct debug_named_value names[] = {
534 DEBUG_NAMED_VALUE(PIPE_USAGE_DEFAULT),
535 DEBUG_NAMED_VALUE(PIPE_USAGE_IMMUTABLE),
536 DEBUG_NAMED_VALUE(PIPE_USAGE_DYNAMIC),
537 DEBUG_NAMED_VALUE(PIPE_USAGE_STREAM),
538 DEBUG_NAMED_VALUE(PIPE_USAGE_STAGING),
539 DEBUG_NAMED_VALUE_END
540 };
541
542 debug_printf("%s: %s\n", msg, debug_dump_enum(names, usage));
543 }
544
545
546 #endif