trace: Use pipe_static_mutex.
[profile/ivi/mesa.git] / src / gallium / drivers / trace / tr_dump.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 /**
30  * @file
31  * Trace dumping functions.
32  *
33  * For now we just use standard XML for dumping the trace calls, as this is
34  * simple to write, parse, and visually inspect, but the actual representation
35  * is abstracted out of this file, so that we can switch to a binary
36  * representation if/when it becomes justified.
37  *
38  * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
39  */
40
41 #include "pipe/p_config.h"
42
43 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE)
44 #include <stdlib.h>
45 #endif
46
47 #include "pipe/p_compiler.h"
48 #include "os/os_thread.h"
49 #include "os/os_stream.h"
50 #include "util/u_debug.h"
51 #include "util/u_memory.h"
52 #include "util/u_string.h"
53 #include "util/u_math.h"
54 #include "util/u_format.h"
55
56 #include "tr_dump.h"
57 #include "tr_screen.h"
58 #include "tr_texture.h"
59
60
61 static struct os_stream *stream = NULL;
62 static unsigned refcount = 0;
63 pipe_static_mutex(call_mutex);
64 static long unsigned call_no = 0;
65 static boolean dumping = FALSE;
66
67
68 static INLINE void
69 trace_dump_write(const char *buf, size_t size)
70 {
71    if(stream)
72       os_stream_write(stream, buf, size);
73 }
74
75
76 static INLINE void
77 trace_dump_writes(const char *s)
78 {
79    trace_dump_write(s, strlen(s));
80 }
81
82
83 static INLINE void
84 trace_dump_writef(const char *format, ...)
85 {
86    static char buf[1024];
87    unsigned len;
88    va_list ap;
89    va_start(ap, format);
90    len = util_vsnprintf(buf, sizeof(buf), format, ap);
91    va_end(ap);
92    trace_dump_write(buf, len);
93 }
94
95
96 static INLINE void
97 trace_dump_escape(const char *str)
98 {
99    const unsigned char *p = (const unsigned char *)str;
100    unsigned char c;
101    while((c = *p++) != 0) {
102       if(c == '<')
103          trace_dump_writes("&lt;");
104       else if(c == '>')
105          trace_dump_writes("&gt;");
106       else if(c == '&')
107          trace_dump_writes("&amp;");
108       else if(c == '\'')
109          trace_dump_writes("&apos;");
110       else if(c == '\"')
111          trace_dump_writes("&quot;");
112       else if(c >= 0x20 && c <= 0x7e)
113          trace_dump_writef("%c", c);
114       else
115          trace_dump_writef("&#%u;", c);
116    }
117 }
118
119
120 static INLINE void
121 trace_dump_indent(unsigned level)
122 {
123    unsigned i;
124    for(i = 0; i < level; ++i)
125       trace_dump_writes("\t");
126 }
127
128
129 static INLINE void
130 trace_dump_newline(void)
131 {
132    trace_dump_writes("\n");
133 }
134
135
136 static INLINE void
137 trace_dump_tag(const char *name)
138 {
139    trace_dump_writes("<");
140    trace_dump_writes(name);
141    trace_dump_writes("/>");
142 }
143
144
145 static INLINE void
146 trace_dump_tag_begin(const char *name)
147 {
148    trace_dump_writes("<");
149    trace_dump_writes(name);
150    trace_dump_writes(">");
151 }
152
153 static INLINE void
154 trace_dump_tag_begin1(const char *name,
155                       const char *attr1, const char *value1)
156 {
157    trace_dump_writes("<");
158    trace_dump_writes(name);
159    trace_dump_writes(" ");
160    trace_dump_writes(attr1);
161    trace_dump_writes("='");
162    trace_dump_escape(value1);
163    trace_dump_writes("'>");
164 }
165
166
167 static INLINE void
168 trace_dump_tag_begin2(const char *name,
169                       const char *attr1, const char *value1,
170                       const char *attr2, const char *value2)
171 {
172    trace_dump_writes("<");
173    trace_dump_writes(name);
174    trace_dump_writes(" ");
175    trace_dump_writes(attr1);
176    trace_dump_writes("=\'");
177    trace_dump_escape(value1);
178    trace_dump_writes("\' ");
179    trace_dump_writes(attr2);
180    trace_dump_writes("=\'");
181    trace_dump_escape(value2);
182    trace_dump_writes("\'>");
183 }
184
185
186 static INLINE void
187 trace_dump_tag_begin3(const char *name,
188                       const char *attr1, const char *value1,
189                       const char *attr2, const char *value2,
190                       const char *attr3, const char *value3)
191 {
192    trace_dump_writes("<");
193    trace_dump_writes(name);
194    trace_dump_writes(" ");
195    trace_dump_writes(attr1);
196    trace_dump_writes("=\'");
197    trace_dump_escape(value1);
198    trace_dump_writes("\' ");
199    trace_dump_writes(attr2);
200    trace_dump_writes("=\'");
201    trace_dump_escape(value2);
202    trace_dump_writes("\' ");
203    trace_dump_writes(attr3);
204    trace_dump_writes("=\'");
205    trace_dump_escape(value3);
206    trace_dump_writes("\'>");
207 }
208
209
210 static INLINE void
211 trace_dump_tag_end(const char *name)
212 {
213    trace_dump_writes("</");
214    trace_dump_writes(name);
215    trace_dump_writes(">");
216 }
217
218 static void
219 trace_dump_trace_close(void)
220 {
221    if(stream) {
222       trace_dump_writes("</trace>\n");
223       os_stream_close(stream);
224       stream = NULL;
225       refcount = 0;
226       call_no = 0;
227    }
228 }
229
230 boolean trace_dump_trace_begin()
231 {
232    const char *filename;
233
234    filename = debug_get_option("GALLIUM_TRACE", NULL);
235    if(!filename)
236       return FALSE;
237
238    if(!stream) {
239
240       stream = os_file_stream_create(filename);
241       if(!stream)
242          return FALSE;
243
244       trace_dump_writes("<?xml version='1.0' encoding='UTF-8'?>\n");
245       trace_dump_writes("<?xml-stylesheet type='text/xsl' href='trace.xsl'?>\n");
246       trace_dump_writes("<trace version='0.1'>\n");
247
248 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE)
249       /* Linux applications rarely cleanup GL / Gallium resources so catch
250        * application exit here */
251       atexit(trace_dump_trace_close);
252 #endif
253    }
254
255    ++refcount;
256
257    return TRUE;
258 }
259
260 boolean trace_dump_trace_enabled(void)
261 {
262    return stream ? TRUE : FALSE;
263 }
264
265 void trace_dump_trace_end(void)
266 {
267    if(stream)
268       if(!--refcount)
269          trace_dump_trace_close();
270 }
271
272 /*
273  * Call lock
274  */
275
276 void trace_dump_call_lock(void)
277 {
278    pipe_mutex_lock(call_mutex);
279 }
280
281 void trace_dump_call_unlock(void)
282 {
283    pipe_mutex_unlock(call_mutex);
284 }
285
286 /*
287  * Dumping control
288  */
289
290 void trace_dumping_start_locked(void)
291 {
292    dumping = TRUE;
293 }
294
295 void trace_dumping_stop_locked(void)
296 {
297    dumping = FALSE;
298 }
299
300 boolean trace_dumping_enabled_locked(void)
301 {
302    return dumping;
303 }
304
305 void trace_dumping_start(void)
306 {
307    pipe_mutex_lock(call_mutex);
308    trace_dumping_start_locked();
309    pipe_mutex_unlock(call_mutex);
310 }
311
312 void trace_dumping_stop(void)
313 {
314    pipe_mutex_lock(call_mutex);
315    trace_dumping_stop_locked();
316    pipe_mutex_unlock(call_mutex);
317 }
318
319 boolean trace_dumping_enabled(void)
320 {
321    boolean ret;
322    pipe_mutex_lock(call_mutex);
323    ret = trace_dumping_enabled_locked();
324    pipe_mutex_unlock(call_mutex);
325    return ret;
326 }
327
328 /*
329  * Dump functions
330  */
331
332 void trace_dump_call_begin_locked(const char *klass, const char *method)
333 {
334    if (!dumping)
335       return;
336
337    ++call_no;
338    trace_dump_indent(1);
339    trace_dump_writes("<call no=\'");
340    trace_dump_writef("%lu", call_no);
341    trace_dump_writes("\' class=\'");
342    trace_dump_escape(klass);
343    trace_dump_writes("\' method=\'");
344    trace_dump_escape(method);
345    trace_dump_writes("\'>");
346    trace_dump_newline();
347 }
348
349 void trace_dump_call_end_locked(void)
350 {
351    if (!dumping)
352       return;
353
354    trace_dump_indent(1);
355    trace_dump_tag_end("call");
356    trace_dump_newline();
357    os_stream_flush(stream);
358 }
359
360 void trace_dump_call_begin(const char *klass, const char *method)
361 {
362    pipe_mutex_lock(call_mutex);
363    trace_dump_call_begin_locked(klass, method);
364 }
365
366 void trace_dump_call_end(void)
367 {
368    trace_dump_call_end_locked();
369    pipe_mutex_unlock(call_mutex);
370 }
371
372 void trace_dump_arg_begin(const char *name)
373 {
374    if (!dumping)
375       return;
376
377    trace_dump_indent(2);
378    trace_dump_tag_begin1("arg", "name", name);
379 }
380
381 void trace_dump_arg_end(void)
382 {
383    if (!dumping)
384       return;
385
386    trace_dump_tag_end("arg");
387    trace_dump_newline();
388 }
389
390 void trace_dump_ret_begin(void)
391 {
392    if (!dumping)
393       return;
394
395    trace_dump_indent(2);
396    trace_dump_tag_begin("ret");
397 }
398
399 void trace_dump_ret_end(void)
400 {
401    if (!dumping)
402       return;
403
404    trace_dump_tag_end("ret");
405    trace_dump_newline();
406 }
407
408 void trace_dump_bool(int value)
409 {
410    if (!dumping)
411       return;
412
413    trace_dump_writef("<bool>%c</bool>", value ? '1' : '0');
414 }
415
416 void trace_dump_int(long long int value)
417 {
418    if (!dumping)
419       return;
420
421    trace_dump_writef("<int>%lli</int>", value);
422 }
423
424 void trace_dump_uint(long long unsigned value)
425 {
426    if (!dumping)
427       return;
428
429    trace_dump_writef("<uint>%llu</uint>", value);
430 }
431
432 void trace_dump_float(double value)
433 {
434    if (!dumping)
435       return;
436
437    trace_dump_writef("<float>%g</float>", value);
438 }
439
440 void trace_dump_bytes(const void *data,
441                       size_t size)
442 {
443    static const char hex_table[16] = "0123456789ABCDEF";
444    const uint8_t *p = data;
445    size_t i;
446
447    if (!dumping)
448       return;
449
450    trace_dump_writes("<bytes>");
451    for(i = 0; i < size; ++i) {
452       uint8_t byte = *p++;
453       char hex[2];
454       hex[0] = hex_table[byte >> 4];
455       hex[1] = hex_table[byte & 0xf];
456       trace_dump_write(hex, 2);
457    }
458    trace_dump_writes("</bytes>");
459 }
460
461 void trace_dump_box_bytes(const void *data,
462                           enum pipe_format format,
463                           const struct pipe_box *box,
464                           unsigned stride,
465                           unsigned slice_stride)
466 {
467    size_t size;
468
469    if (slice_stride)
470       size = box->depth * slice_stride;
471    else if (stride)
472       size = util_format_get_nblocksy(format, box->height) * stride;
473    else {
474       size = util_format_get_nblocksx(format, box->width) * util_format_get_blocksize(format);
475    }
476
477    trace_dump_bytes(data, size);
478 }
479
480 void trace_dump_string(const char *str)
481 {
482    if (!dumping)
483       return;
484
485    trace_dump_writes("<string>");
486    trace_dump_escape(str);
487    trace_dump_writes("</string>");
488 }
489
490 void trace_dump_enum(const char *value)
491 {
492    if (!dumping)
493       return;
494
495    trace_dump_writes("<enum>");
496    trace_dump_escape(value);
497    trace_dump_writes("</enum>");
498 }
499
500 void trace_dump_array_begin(void)
501 {
502    if (!dumping)
503       return;
504
505    trace_dump_writes("<array>");
506 }
507
508 void trace_dump_array_end(void)
509 {
510    if (!dumping)
511       return;
512
513    trace_dump_writes("</array>");
514 }
515
516 void trace_dump_elem_begin(void)
517 {
518    if (!dumping)
519       return;
520
521    trace_dump_writes("<elem>");
522 }
523
524 void trace_dump_elem_end(void)
525 {
526    if (!dumping)
527       return;
528
529    trace_dump_writes("</elem>");
530 }
531
532 void trace_dump_struct_begin(const char *name)
533 {
534    if (!dumping)
535       return;
536
537    trace_dump_writef("<struct name='%s'>", name);
538 }
539
540 void trace_dump_struct_end(void)
541 {
542    if (!dumping)
543       return;
544
545    trace_dump_writes("</struct>");
546 }
547
548 void trace_dump_member_begin(const char *name)
549 {
550    if (!dumping)
551       return;
552
553    trace_dump_writef("<member name='%s'>", name);
554 }
555
556 void trace_dump_member_end(void)
557 {
558    if (!dumping)
559       return;
560
561    trace_dump_writes("</member>");
562 }
563
564 void trace_dump_null(void)
565 {
566    if (!dumping)
567       return;
568
569    trace_dump_writes("<null/>");
570 }
571
572 void trace_dump_ptr(const void *value)
573 {
574    if (!dumping)
575       return;
576
577    if(value)
578       trace_dump_writef("<ptr>0x%08lx</ptr>", (unsigned long)(uintptr_t)value);
579    else
580       trace_dump_null();
581 }
582
583
584 void trace_dump_resource_ptr(struct pipe_resource *_resource)
585 {
586    if (!dumping)
587       return;
588
589    if (_resource) {
590       struct trace_resource *tr_resource = trace_resource(_resource);
591       trace_dump_ptr(tr_resource->resource);
592    } else {
593       trace_dump_null();
594    }
595 }
596
597 void trace_dump_surface_ptr(struct pipe_surface *_surface)
598 {
599    if (!dumping)
600       return;
601
602    if (_surface) {
603       struct trace_surface *tr_surf = trace_surface(_surface);
604       trace_dump_ptr(tr_surf->surface);
605    } else {
606       trace_dump_null();
607    }
608 }
609
610 void trace_dump_transfer_ptr(struct pipe_transfer *_transfer)
611 {
612    if (!dumping)
613       return;
614
615    if (_transfer) {
616       struct trace_transfer *tr_tran = trace_transfer(_transfer);
617       trace_dump_ptr(tr_tran->transfer);
618    } else {
619       trace_dump_null();
620    }
621 }