gallium: Be less verbose with debug options messages.
[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
54
55 #include "pipe/p_compiler.h"
56 #include "pipe/p_util.h"
57 #include "pipe/p_debug.h"
58 #include "pipe/p_format.h"
59 #include "util/u_string.h"
60
61
62 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
63 static INLINE void
64 _EngDebugPrint(const char *format, ...)
65 {
66 va_list ap;
67 va_start(ap, format);
68 EngDebugPrint("", (PCHAR)format, ap);
69 va_end(ap);
70 }
71 #endif
72
73
74 void _debug_vprintf(const char *format, va_list ap)
75 {
76 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
77 #ifndef WINCE
78 /* EngDebugPrint does not handle float point arguments, so we need to use
79 * our own vsnprintf implementation. It is also very slow, so buffer until
80 * we find a newline. */
81 static char buf[512 + 1] = {'\0'};
82 size_t len = strlen(buf);
83 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
84 if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
85 _EngDebugPrint("%s", buf);
86 buf[0] = '\0';
87 }
88 #else
89 /* TODO: Implement debug print for WINCE */
90 #endif
91 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
92 /* EngDebugPrint does not handle float point arguments, so we need to use
93 * our own vsnprintf implementation. It is also very slow, so buffer until
94 * we find a newline. */
95 static char buf[512 + 1] = {'\0'};
96 size_t len = strlen(buf);
97 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
98 if(ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
99 OutputDebugStringA(buf);
100 buf[0] = '\0';
101 }
102 #else
103 vfprintf(stderr, format, ap);
104 #endif
105 }
106
107
108 #ifdef DEBUG
109 void debug_print_blob( const char *name,
110 const void *blob,
111 unsigned size )
112 {
113 const unsigned *ublob = (const unsigned *)blob;
114 unsigned i;
115
116 debug_printf("%s (%d dwords%s)\n", name, size/4,
117 size%4 ? "... plus a few bytes" : "");
118
119 for (i = 0; i < size/4; i++) {
120 debug_printf("%d:\t%08x\n", i, ublob[i]);
121 }
122 }
123 #endif
124
125
126 void _debug_break(void)
127 {
128 #if defined(PIPE_ARCH_X86) && defined(PIPE_CC_GCC)
129 __asm("int3");
130 #elif defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)
131 _asm {int 3};
132 #elif defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
133 EngDebugBreak();
134 #else
135 abort();
136 #endif
137 }
138
139
140 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
141 static const char *
142 find(const char *start, const char *end, char c)
143 {
144 const char *p;
145 for(p = start; !end || p != end; ++p) {
146 if(*p == c)
147 return p;
148 if(*p < 32)
149 break;
150 }
151 return NULL;
152 }
153
154 static int
155 compare(const char *start, const char *end, const char *s)
156 {
157 const char *p, *q;
158 for(p = start, q = s; p != end && *q != '\0'; ++p, ++q) {
159 if(*p != *q)
160 return 0;
161 }
162 return p == end && *q == '\0';
163 }
164
165 static void
166 copy(char *dst, const char *start, const char *end, size_t n)
167 {
168 const char *p;
169 char *q;
170 for(p = start, q = dst, n = n - 1; p != end && n; ++p, ++q, --n)
171 *q = *p;
172 *q = '\0';
173 }
174 #endif
175
176
177 static INLINE const char *
178 _debug_get_option(const char *name)
179 {
180 #if defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
181 /* EngMapFile creates the file if it does not exists, so it must either be
182 * disabled on release versions (or put in a less conspicuous place). */
183 #ifdef DEBUG
184 const char *result = NULL;
185 ULONG_PTR iFile = 0;
186 const void *pMap = NULL;
187 const char *sol, *eol, *sep;
188 static char output[1024];
189
190 pMap = EngMapFile(L"\\??\\c:\\gallium.cfg", 0, &iFile);
191 if(pMap) {
192 sol = (const char *)pMap;
193 while(1) {
194 /* TODO: handle LF line endings */
195 eol = find(sol, NULL, '\r');
196 if(!eol || eol == sol)
197 break;
198 sep = find(sol, eol, '=');
199 if(!sep)
200 break;
201 if(compare(sol, sep, name)) {
202 copy(output, sep + 1, eol, sizeof(output));
203 result = output;
204 break;
205 }
206 sol = eol + 2;
207 }
208 EngUnmapFile(iFile);
209 }
210 return result;
211 #else
212 return NULL;
213 #endif
214 #elif defined(PIPE_SUBSYSTEM_WINDOWS_CE)
215 /* TODO: implement */
216 return NULL;
217 #else
218 return getenv(name);
219 #endif
220 }
221
222 const char *
223 debug_get_option(const char *name, const char *dfault)
224 {
225 const char *result;
226
227 result = _debug_get_option(name);
228 if(!result)
229 result = dfault;
230
231 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
232
233 return result;
234 }
235
236 boolean
237 debug_get_bool_option(const char *name, boolean dfault)
238 {
239 const char *str = _debug_get_option(name);
240 boolean result;
241
242 if(str == NULL)
243 result = dfault;
244 else if(!util_strcmp(str, "n"))
245 result = FALSE;
246 else if(!util_strcmp(str, "no"))
247 result = FALSE;
248 else if(!util_strcmp(str, "0"))
249 result = FALSE;
250 else if(!util_strcmp(str, "f"))
251 result = FALSE;
252 else if(!util_strcmp(str, "false"))
253 result = FALSE;
254 else
255 result = TRUE;
256
257 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
258
259 return result;
260 }
261
262
263 long
264 debug_get_num_option(const char *name, long dfault)
265 {
266 long result;
267 const char *str;
268
269 str = _debug_get_option(name);
270 if(!str)
271 result = dfault;
272 else {
273 long sign;
274 char c;
275 c = *str++;
276 if(c == '-') {
277 sign = -1;
278 c = *str++;
279 }
280 else {
281 sign = 1;
282 }
283 result = 0;
284 while('0' <= c && c <= '9') {
285 result = result*10 + (c - '0');
286 c = *str++;
287 }
288 result *= sign;
289 }
290
291 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
292
293 return result;
294 }
295
296
297 unsigned long
298 debug_get_flags_option(const char *name,
299 const struct debug_named_value *flags,
300 unsigned long dfault)
301 {
302 unsigned long result;
303 const char *str;
304
305 str = _debug_get_option(name);
306 if(!str)
307 result = dfault;
308 else {
309 result = 0;
310 while( flags->name ) {
311 if (!util_strcmp(str, "all") || util_strstr(str, flags->name ))
312 result |= flags->value;
313 ++flags;
314 }
315 }
316
317 debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
318
319 return result;
320 }
321
322
323 void _debug_assert_fail(const char *expr,
324 const char *file,
325 unsigned line,
326 const char *function)
327 {
328 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
329 if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", TRUE))
330 debug_break();
331 else
332 _debug_printf("continuing...\n");
333 }
334
335
336 const char *
337 debug_dump_enum(const struct debug_named_value *names,
338 unsigned long value)
339 {
340 static char rest[256];
341
342 while(names->name) {
343 if(names->value == value)
344 return names->name;
345 ++names;
346 }
347
348 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
349 return rest;
350 }
351
352
353 const char *
354 debug_dump_flags(const struct debug_named_value *names,
355 unsigned long value)
356 {
357 static char output[4096];
358 static char rest[256];
359 int first = 1;
360
361 output[0] = '\0';
362
363 while(names->name) {
364 if((names->value & value) == names->value) {
365 if (!first)
366 util_strncat(output, "|", sizeof(output));
367 else
368 first = 0;
369 util_strncat(output, names->name, sizeof(output));
370 value &= ~names->value;
371 }
372 ++names;
373 }
374
375 if (value) {
376 if (!first)
377 util_strncat(output, "|", sizeof(output));
378 else
379 first = 0;
380
381 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
382 util_strncat(output, rest, sizeof(output));
383 }
384
385 if(first)
386 return "0";
387
388 return output;
389 }
390
391
392 static const struct debug_named_value pipe_format_names[] = {
393 #ifdef DEBUG
394 DEBUG_NAMED_VALUE(PIPE_FORMAT_NONE),
395 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8R8G8B8_UNORM),
396 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8R8G8B8_UNORM),
397 DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8A8_UNORM),
398 DEBUG_NAMED_VALUE(PIPE_FORMAT_B8G8R8X8_UNORM),
399 DEBUG_NAMED_VALUE(PIPE_FORMAT_A1R5G5B5_UNORM),
400 DEBUG_NAMED_VALUE(PIPE_FORMAT_A4R4G4B4_UNORM),
401 DEBUG_NAMED_VALUE(PIPE_FORMAT_R5G6B5_UNORM),
402 DEBUG_NAMED_VALUE(PIPE_FORMAT_A2B10G10R10_UNORM),
403 DEBUG_NAMED_VALUE(PIPE_FORMAT_L8_UNORM),
404 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8_UNORM),
405 DEBUG_NAMED_VALUE(PIPE_FORMAT_I8_UNORM),
406 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8L8_UNORM),
407 DEBUG_NAMED_VALUE(PIPE_FORMAT_L16_UNORM),
408 DEBUG_NAMED_VALUE(PIPE_FORMAT_YCBCR),
409 DEBUG_NAMED_VALUE(PIPE_FORMAT_YCBCR_REV),
410 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z16_UNORM),
411 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z32_UNORM),
412 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z32_FLOAT),
413 DEBUG_NAMED_VALUE(PIPE_FORMAT_S8Z24_UNORM),
414 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z24S8_UNORM),
415 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8Z24_UNORM),
416 DEBUG_NAMED_VALUE(PIPE_FORMAT_Z24X8_UNORM),
417 DEBUG_NAMED_VALUE(PIPE_FORMAT_S8_UNORM),
418 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64_FLOAT),
419 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64_FLOAT),
420 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64B64_FLOAT),
421 DEBUG_NAMED_VALUE(PIPE_FORMAT_R64G64B64A64_FLOAT),
422 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_FLOAT),
423 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_FLOAT),
424 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_FLOAT),
425 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_FLOAT),
426 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_UNORM),
427 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_UNORM),
428 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_UNORM),
429 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_UNORM),
430 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_USCALED),
431 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_USCALED),
432 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_USCALED),
433 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_USCALED),
434 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_SNORM),
435 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_SNORM),
436 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_SNORM),
437 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_SNORM),
438 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32_SSCALED),
439 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32_SSCALED),
440 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32_SSCALED),
441 DEBUG_NAMED_VALUE(PIPE_FORMAT_R32G32B32A32_SSCALED),
442 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_UNORM),
443 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_UNORM),
444 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_UNORM),
445 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_UNORM),
446 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_USCALED),
447 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_USCALED),
448 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_USCALED),
449 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_USCALED),
450 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_SNORM),
451 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_SNORM),
452 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_SNORM),
453 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_SNORM),
454 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16_SSCALED),
455 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16_SSCALED),
456 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16_SSCALED),
457 DEBUG_NAMED_VALUE(PIPE_FORMAT_R16G16B16A16_SSCALED),
458 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_UNORM),
459 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_UNORM),
460 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_UNORM),
461 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_UNORM),
462 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_UNORM),
463 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_USCALED),
464 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_USCALED),
465 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_USCALED),
466 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_USCALED),
467 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_USCALED),
468 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_SNORM),
469 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_SNORM),
470 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SNORM),
471 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SNORM),
472 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SNORM),
473 DEBUG_NAMED_VALUE(PIPE_FORMAT_B6G5R5_SNORM),
474 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8B8G8R8_SNORM),
475 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8B8G8R8_SNORM),
476 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8_SSCALED),
477 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8_SSCALED),
478 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SSCALED),
479 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SSCALED),
480 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SSCALED),
481 DEBUG_NAMED_VALUE(PIPE_FORMAT_L8_SRGB),
482 DEBUG_NAMED_VALUE(PIPE_FORMAT_A8_L8_SRGB),
483 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8_SRGB),
484 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8A8_SRGB),
485 DEBUG_NAMED_VALUE(PIPE_FORMAT_R8G8B8X8_SRGB),
486 DEBUG_NAMED_VALUE(PIPE_FORMAT_X8UB8UG8SR8S_NORM),
487 DEBUG_NAMED_VALUE(PIPE_FORMAT_B6UG5SR5S_NORM),
488 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_RGB),
489 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT1_RGBA),
490 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT3_RGBA),
491 DEBUG_NAMED_VALUE(PIPE_FORMAT_DXT5_RGBA),
492 #endif
493 DEBUG_NAMED_VALUE_END
494 };
495
496 #ifdef DEBUG
497 void debug_print_format(const char *msg, unsigned fmt )
498 {
499 debug_printf("%s: %s\n", msg, debug_dump_enum(pipe_format_names, fmt));
500 }
501 #endif
502
503 char *pf_sprint_name( char *str, enum pipe_format format )
504 {
505 strcpy( str, debug_dump_enum(pipe_format_names, format) );
506 return str;
507 }
508
509
510 #ifdef DEBUG
511 void debug_dump_image(const char *prefix,
512 unsigned format, unsigned cpp,
513 unsigned width, unsigned height,
514 unsigned pitch,
515 const void *data)
516 {
517 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
518 static unsigned no = 0;
519 char filename[256];
520 WCHAR wfilename[sizeof(filename)];
521 ULONG_PTR iFile = 0;
522 struct {
523 unsigned format;
524 unsigned cpp;
525 unsigned width;
526 unsigned height;
527 } header;
528 unsigned char *pMap = NULL;
529 unsigned i;
530
531 util_snprintf(filename, sizeof(filename), "\\??\\c:\\%03u%s.raw", ++no, prefix);
532 for(i = 0; i < sizeof(filename); ++i)
533 wfilename[i] = (WCHAR)filename[i];
534
535 pMap = (unsigned char *)EngMapFile(wfilename, sizeof(header) + cpp*width*height, &iFile);
536 if(!pMap)
537 return;
538
539 header.format = format;
540 header.cpp = cpp;
541 header.width = width;
542 header.height = height;
543 memcpy(pMap, &header, sizeof(header));
544 pMap += sizeof(header);
545
546 for(i = 0; i < height; ++i) {
547 memcpy(pMap, (unsigned char *)data + cpp*pitch*i, cpp*width);
548 pMap += cpp*width;
549 }
550
551 EngUnmapFile(iFile);
552 #endif
553 }
554 #endif