56eecaab62256371ecbd25e7a96b3e3037efa511
[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 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
34 #include <windows.h>
35 #include <winddi.h>
36 #else
37 #include <stdio.h>
38 #include <stdlib.h>
39 #endif
40
41 #include "pipe/p_compiler.h"
42 #include "pipe/p_util.h"
43 #include "pipe/p_debug.h"
44 #include "pipe/p_format.h"
45 #include "util/u_string.h"
46
47
48 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
49 static INLINE void
50 _EngDebugPrint(const char *format, ...)
51 {
52 va_list ap;
53 va_start(ap, format);
54 EngDebugPrint("", (PCHAR)format, ap);
55 va_end(ap);
56 }
57 #endif
58
59
60 void _debug_vprintf(const char *format, va_list ap)
61 {
62 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
63 #ifndef WINCE
64 /* EngDebugPrint does not handle float point arguments, so we need to use
65 * our own vsnprintf implementation. It is also very slow, so buffer until
66 * we find a newline. */
67 static char buf[512 + 1] = {'\0'};
68 size_t len = strlen(buf);
69 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
70 if(ret > (int)(sizeof(buf) - len - 1) || strchr(buf + len, '\n')) {
71 _EngDebugPrint("%s", buf);
72 buf[0] = '\0';
73 }
74 #else
75 /* TODO: Implement debug print for WINCE */
76 #endif
77 #else
78 vfprintf(stderr, format, ap);
79 #endif
80 }
81
82
83 #ifdef DEBUG
84 void debug_print_blob( const char *name,
85 const void *blob,
86 unsigned size )
87 {
88 const unsigned *ublob = (const unsigned *)blob;
89 unsigned i;
90
91 debug_printf("%s (%d dwords%s)\n", name, size/4,
92 size%4 ? "... plus a few bytes" : "");
93
94 for (i = 0; i < size/4; i++) {
95 debug_printf("%d:\t%08x\n", i, ublob[i]);
96 }
97 }
98 #endif
99
100
101 void _debug_break(void)
102 {
103 #if (defined(__i386__) || defined(__386__)) && defined(__GNUC__)
104 __asm("int3");
105 #elif (defined(__i386__) || defined(__386__)) && defined(__MSC__)
106 _asm {int 3};
107 #elif defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
108 EngDebugBreak();
109 #else
110 abort();
111 #endif
112 }
113
114
115 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
116 static const char *
117 find(const char *start, const char *end, char c)
118 {
119 const char *p;
120 for(p = start; !end || p != end; ++p) {
121 if(*p == c)
122 return p;
123 if(*p < 32)
124 break;
125 }
126 return NULL;
127 }
128
129 static int
130 compare(const char *start, const char *end, const char *s)
131 {
132 const char *p, *q;
133 for(p = start, q = s; p != end && *q != '\0'; ++p, ++q) {
134 if(*p != *q)
135 return 0;
136 }
137 return p == end && *q == '\0';
138 }
139
140 static void
141 copy(char *dst, const char *start, const char *end, size_t n)
142 {
143 const char *p;
144 char *q;
145 for(p = start, q = dst, n = n - 1; p != end && n; ++p, ++q, --n)
146 *q = *p;
147 *q = '\0';
148 }
149 #endif
150
151
152 const char *
153 debug_get_option(const char *name, const char *dfault)
154 {
155 const char *result;
156 #ifdef PIPE_SUBSYSTEM_WINDOWS_DISPLAY
157 ULONG_PTR iFile = 0;
158 const void *pMap = NULL;
159 const char *sol, *eol, *sep;
160 static char output[1024];
161
162 result = dfault;
163 /* XXX: this creates the file if it does not exists, so it must either be
164 * disabled on release versions, or put in a less conspicuous place.
165 */
166 pMap = EngMapFile(L"\\??\\c:\\gallium.cfg", 0, &iFile);
167 if(pMap) {
168 sol = (const char *)pMap;
169 while(1) {
170 /* TODO: handle LF line endings */
171 eol = find(sol, NULL, '\r');
172 if(!eol || eol == sol)
173 break;
174 sep = find(sol, eol, '=');
175 if(!sep)
176 break;
177 if(compare(sol, sep, name)) {
178 copy(output, sep + 1, eol, sizeof(output));
179 result = output;
180 break;
181 }
182 sol = eol + 2;
183 }
184 EngUnmapFile(iFile);
185 }
186 #else
187
188 result = getenv(name);
189 if(!result)
190 result = dfault;
191 #endif
192
193 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? result : "(null)");
194
195 return result;
196 }
197
198 boolean
199 debug_get_bool_option(const char *name, boolean dfault)
200 {
201 const char *str = debug_get_option(name, NULL);
202 boolean result;
203
204 if(str == NULL)
205 result = dfault;
206 else if(!strcmp(str, "n"))
207 result = FALSE;
208 else if(!strcmp(str, "no"))
209 result = FALSE;
210 else if(!strcmp(str, "0"))
211 result = FALSE;
212 else if(!strcmp(str, "f"))
213 result = FALSE;
214 else if(!strcmp(str, "false"))
215 result = FALSE;
216 else
217 result = TRUE;
218
219 debug_printf("%s: %s = %s\n", __FUNCTION__, name, result ? "TRUE" : "FALSE");
220
221 return result;
222 }
223
224
225 long
226 debug_get_num_option(const char *name, long dfault)
227 {
228 /* FIXME */
229 return dfault;
230 }
231
232
233 unsigned long
234 debug_get_flags_option(const char *name,
235 const struct debug_named_value *flags,
236 unsigned long dfault)
237 {
238 unsigned long result;
239 const char *str;
240
241 str = debug_get_option(name, NULL);
242 if(!str)
243 result = dfault;
244 else {
245 result = 0;
246 while( flags->name ) {
247 if (!strcmp(str, "all") || strstr(str, flags->name ))
248 result |= flags->value;
249 ++flags;
250 }
251 }
252
253 debug_printf("%s: %s = 0x%lx\n", __FUNCTION__, name, result);
254
255 return result;
256 }
257
258
259 void _debug_assert_fail(const char *expr,
260 const char *file,
261 unsigned line,
262 const char *function)
263 {
264 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", file, line, function, expr);
265 if (debug_get_bool_option("GALLIUM_ABORT_ON_ASSERT", TRUE))
266 debug_break();
267 else
268 _debug_printf("continuing...\n");
269 }
270
271
272 const char *
273 debug_dump_enum(const struct debug_named_value *names,
274 unsigned long value)
275 {
276 static char rest[256];
277
278 while(names->name) {
279 if(names->value == value)
280 return names->name;
281 ++names;
282 }
283
284 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
285 return rest;
286 }
287
288
289 const char *
290 debug_dump_flags(const struct debug_named_value *names,
291 unsigned long value)
292 {
293 static char output[4096];
294 static char rest[256];
295 int first = 1;
296
297 output[0] = '\0';
298
299 while(names->name) {
300 if((names->value & value) == names->value) {
301 if (!first)
302 strncat(output, "|", sizeof(output));
303 else
304 first = 0;
305 strncat(output, names->name, sizeof(output));
306 value &= ~names->value;
307 }
308 ++names;
309 }
310
311 if (value) {
312 if (!first)
313 strncat(output, "|", sizeof(output));
314 else
315 first = 0;
316
317 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
318 strncat(output, rest, sizeof(output));
319 }
320
321 if(first)
322 return "0";
323
324 return output;
325 }
326
327
328
329
330
331
332 char *pf_sprint_name( char *str, enum pipe_format format )
333 {
334 strcpy( str, "PIPE_FORMAT_" );
335 switch (pf_layout( format )) {
336 case PIPE_FORMAT_LAYOUT_RGBAZS:
337 {
338 pipe_format_rgbazs_t rgbazs = (pipe_format_rgbazs_t) format;
339 uint i;
340 uint scale = 1 << (pf_exp8( rgbazs ) * 3);
341
342 for (i = 0; i < 4; i++) {
343 uint size = pf_size_xyzw( rgbazs, i );
344
345 if (size == 0) {
346 break;
347 }
348 switch (pf_swizzle_xyzw( rgbazs, i )) {
349 case PIPE_FORMAT_COMP_R:
350 strcat( str, "R" );
351 break;
352 case PIPE_FORMAT_COMP_G:
353 strcat( str, "G" );
354 break;
355 case PIPE_FORMAT_COMP_B:
356 strcat( str, "B" );
357 break;
358 case PIPE_FORMAT_COMP_A:
359 strcat( str, "A" );
360 break;
361 case PIPE_FORMAT_COMP_0:
362 strcat( str, "0" );
363 break;
364 case PIPE_FORMAT_COMP_1:
365 strcat( str, "1" );
366 break;
367 case PIPE_FORMAT_COMP_Z:
368 strcat( str, "Z" );
369 break;
370 case PIPE_FORMAT_COMP_S:
371 strcat( str, "S" );
372 break;
373 }
374 util_snprintf( &str[strlen( str )], 32, "%u", size * scale );
375 }
376 if (i != 0) {
377 strcat( str, "_" );
378 }
379 switch (pf_type( rgbazs )) {
380 case PIPE_FORMAT_TYPE_UNKNOWN:
381 strcat( str, "NONE" );
382 break;
383 case PIPE_FORMAT_TYPE_FLOAT:
384 strcat( str, "FLOAT" );
385 break;
386 case PIPE_FORMAT_TYPE_UNORM:
387 strcat( str, "UNORM" );
388 break;
389 case PIPE_FORMAT_TYPE_SNORM:
390 strcat( str, "SNORM" );
391 break;
392 case PIPE_FORMAT_TYPE_USCALED:
393 strcat( str, "USCALED" );
394 break;
395 case PIPE_FORMAT_TYPE_SSCALED:
396 strcat( str, "SSCALED" );
397 break;
398 }
399 }
400 break;
401 case PIPE_FORMAT_LAYOUT_YCBCR:
402 {
403 pipe_format_ycbcr_t ycbcr = (pipe_format_ycbcr_t) format;
404
405 strcat( str, "YCBCR" );
406 if (pf_rev( ycbcr )) {
407 strcat( str, "_REV" );
408 }
409 }
410 break;
411 }
412 return str;
413 }
414
415
416 void debug_print_format(const char *msg, unsigned fmt )
417 {
418 char fmtstr[80];
419
420 pf_sprint_name(fmtstr, (enum pipe_format)fmt);
421
422 debug_printf("%s: %s\n", msg, fmtstr);
423 }