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
_debug_vprintf(const char * format,va_list ap)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
_pipe_debug_message(struct pipe_debug_callback * cb,unsigned * id,enum pipe_debug_type type,const char * fmt,...)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
debug_disable_error_message_boxes(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
debug_print_blob(const char * name,const void * blob,unsigned size)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
debug_get_option_should_print(void)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 *
debug_get_option(const char * name,const char * dfault)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
debug_get_bool_option(const char * name,boolean dfault)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
debug_get_num_option(const char * name,long dfault)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
str_has_option(const char * str,const char * name)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
debug_get_flags_option(const char * name,const struct debug_named_value * flags,uint64_t dfault)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
_debug_assert_fail(const char * expr,const char * file,unsigned line,const char * function)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 *
debug_dump_enum(const struct debug_named_value * names,unsigned long value)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 *
debug_dump_enum_noprefix(const struct debug_named_value * names,const char * prefix,unsigned long value)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 *
debug_dump_flags(const struct debug_named_value * names,unsigned long value)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
debug_print_format(const char * msg,unsigned fmt)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 *
u_prim_name(enum pipe_prim_type prim)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
debug_funclog_enter(const char * f,UNUSED const int line,UNUSED const char * file)447 debug_funclog_enter(const char* f, UNUSED const int line,
448 UNUSED const char* file)
449 {
450 int i;
451
452 for (i = 0; i < fl_indent; i++)
453 debug_printf(" ");
454 debug_printf("%s\n", f);
455
456 assert(fl_indent < 1023);
457 fl_function[fl_indent++] = f;
458
459 return 0;
460 }
461
462 void
debug_funclog_exit(const char * f,UNUSED const int line,UNUSED const char * file)463 debug_funclog_exit(const char* f, UNUSED const int line,
464 UNUSED const char* file)
465 {
466 --fl_indent;
467 assert(fl_indent >= 0);
468 assert(fl_function[fl_indent] == f);
469 }
470
471 void
debug_funclog_enter_exit(const char * f,UNUSED const int line,UNUSED const char * file)472 debug_funclog_enter_exit(const char* f, UNUSED const int line,
473 UNUSED const char* file)
474 {
475 int i;
476 for (i = 0; i < fl_indent; i++)
477 debug_printf(" ");
478 debug_printf("%s\n", f);
479 }
480 #endif
481
482
483
484 #ifdef DEBUG
485 /**
486 * Print PIPE_TRANSFER_x flags with a message.
487 */
488 void
debug_print_transfer_flags(const char * msg,unsigned usage)489 debug_print_transfer_flags(const char *msg, unsigned usage)
490 {
491 debug_printf("%s: ", msg);
492 util_dump_transfer_usage(stdout, usage);
493 printf("\n");
494 }
495
496
497 /**
498 * Print PIPE_BIND_x flags with a message.
499 */
500 void
debug_print_bind_flags(const char * msg,unsigned usage)501 debug_print_bind_flags(const char *msg, unsigned usage)
502 {
503 static const struct debug_named_value names[] = {
504 DEBUG_NAMED_VALUE(PIPE_BIND_DEPTH_STENCIL),
505 DEBUG_NAMED_VALUE(PIPE_BIND_RENDER_TARGET),
506 DEBUG_NAMED_VALUE(PIPE_BIND_BLENDABLE),
507 DEBUG_NAMED_VALUE(PIPE_BIND_SAMPLER_VIEW),
508 DEBUG_NAMED_VALUE(PIPE_BIND_VERTEX_BUFFER),
509 DEBUG_NAMED_VALUE(PIPE_BIND_INDEX_BUFFER),
510 DEBUG_NAMED_VALUE(PIPE_BIND_CONSTANT_BUFFER),
511 DEBUG_NAMED_VALUE(PIPE_BIND_DISPLAY_TARGET),
512 DEBUG_NAMED_VALUE(PIPE_BIND_STREAM_OUTPUT),
513 DEBUG_NAMED_VALUE(PIPE_BIND_CURSOR),
514 DEBUG_NAMED_VALUE(PIPE_BIND_CUSTOM),
515 DEBUG_NAMED_VALUE(PIPE_BIND_GLOBAL),
516 DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_BUFFER),
517 DEBUG_NAMED_VALUE(PIPE_BIND_SHADER_IMAGE),
518 DEBUG_NAMED_VALUE(PIPE_BIND_COMPUTE_RESOURCE),
519 DEBUG_NAMED_VALUE(PIPE_BIND_COMMAND_ARGS_BUFFER),
520 DEBUG_NAMED_VALUE(PIPE_BIND_SCANOUT),
521 DEBUG_NAMED_VALUE(PIPE_BIND_SHARED),
522 DEBUG_NAMED_VALUE(PIPE_BIND_LINEAR),
523 DEBUG_NAMED_VALUE_END
524 };
525
526 debug_printf("%s: %s\n", msg, debug_dump_flags(names, usage));
527 }
528
529
530 /**
531 * Print PIPE_USAGE_x enum values with a message.
532 */
533 void
debug_print_usage_enum(const char * msg,enum pipe_resource_usage usage)534 debug_print_usage_enum(const char *msg, enum pipe_resource_usage usage)
535 {
536 static const struct debug_named_value names[] = {
537 DEBUG_NAMED_VALUE(PIPE_USAGE_DEFAULT),
538 DEBUG_NAMED_VALUE(PIPE_USAGE_IMMUTABLE),
539 DEBUG_NAMED_VALUE(PIPE_USAGE_DYNAMIC),
540 DEBUG_NAMED_VALUE(PIPE_USAGE_STREAM),
541 DEBUG_NAMED_VALUE(PIPE_USAGE_STAGING),
542 DEBUG_NAMED_VALUE_END
543 };
544
545 debug_printf("%s: %s\n", msg, debug_dump_enum(names, usage));
546 }
547
548
549 #endif
550