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