1affafdddc6c310ea95055b5b8bd075914ea2c86
[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
54 #include "tr_dump.h"
55 #include "tr_screen.h"
56 #include "tr_texture.h"
57 #include "tr_buffer.h"
58
59
60 static struct os_stream *stream = NULL;
61 static unsigned refcount = 0;
62 static pipe_mutex call_mutex;
63 static long unsigned call_no = 0;
64 static boolean dumping = FALSE;
65 static boolean initialized = 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       pipe_mutex_destroy(call_mutex);
228    }
229 }
230
231 void trace_dump_init()
232 {
233    if (initialized)
234       return;
235
236    pipe_mutex_init(call_mutex);
237    dumping = FALSE;
238    initialized = TRUE;
239 }
240
241 boolean trace_dump_trace_begin()
242 {
243    const char *filename;
244
245    assert(initialized);
246
247    filename = debug_get_option("GALLIUM_TRACE", NULL);
248    if(!filename)
249       return FALSE;
250
251    if(!stream) {
252
253       stream = os_file_stream_create(filename);
254       if(!stream)
255          return FALSE;
256
257       trace_dump_writes("<?xml version='1.0' encoding='UTF-8'?>\n");
258       trace_dump_writes("<?xml-stylesheet type='text/xsl' href='trace.xsl'?>\n");
259       trace_dump_writes("<trace version='0.1'>\n");
260
261 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE)
262       /* Linux applications rarely cleanup GL / Gallium resources so catch
263        * application exit here */
264       atexit(trace_dump_trace_close);
265 #endif
266    }
267
268    ++refcount;
269
270    return TRUE;
271 }
272
273 boolean trace_dump_trace_enabled(void)
274 {
275    return stream ? TRUE : FALSE;
276 }
277
278 void trace_dump_trace_end(void)
279 {
280    if(stream)
281       if(!--refcount)
282          trace_dump_trace_close();
283 }
284
285 /*
286  * Call lock
287  */
288
289 void trace_dump_call_lock(void)
290 {
291    pipe_mutex_lock(call_mutex);
292 }
293
294 void trace_dump_call_unlock(void)
295 {
296    pipe_mutex_unlock(call_mutex);
297 }
298
299 /*
300  * Dumping control
301  */
302
303 void trace_dumping_start_locked(void)
304 {
305    dumping = TRUE;
306 }
307
308 void trace_dumping_stop_locked(void)
309 {
310    dumping = FALSE;
311 }
312
313 boolean trace_dumping_enabled_locked(void)
314 {
315    return dumping;
316 }
317
318 void trace_dumping_start(void)
319 {
320    pipe_mutex_lock(call_mutex);
321    trace_dumping_start_locked();
322    pipe_mutex_unlock(call_mutex);
323 }
324
325 void trace_dumping_stop(void)
326 {
327    pipe_mutex_lock(call_mutex);
328    trace_dumping_stop_locked();
329    pipe_mutex_unlock(call_mutex);
330 }
331
332 boolean trace_dumping_enabled(void)
333 {
334    boolean ret;
335    pipe_mutex_lock(call_mutex);
336    ret = trace_dumping_enabled_locked();
337    pipe_mutex_unlock(call_mutex);
338    return ret;
339 }
340
341 /*
342  * Dump functions
343  */
344
345 void trace_dump_call_begin_locked(const char *klass, const char *method)
346 {
347    if (!dumping)
348       return;
349
350    ++call_no;
351    trace_dump_indent(1);
352    trace_dump_writes("<call no=\'");
353    trace_dump_writef("%lu", call_no);
354    trace_dump_writes("\' class=\'");
355    trace_dump_escape(klass);
356    trace_dump_writes("\' method=\'");
357    trace_dump_escape(method);
358    trace_dump_writes("\'>");
359    trace_dump_newline();
360 }
361
362 void trace_dump_call_end_locked(void)
363 {
364    if (!dumping)
365       return;
366
367    trace_dump_indent(1);
368    trace_dump_tag_end("call");
369    trace_dump_newline();
370    os_stream_flush(stream);
371 }
372
373 void trace_dump_call_begin(const char *klass, const char *method)
374 {
375    pipe_mutex_lock(call_mutex);
376    trace_dump_call_begin_locked(klass, method);
377 }
378
379 void trace_dump_call_end(void)
380 {
381    trace_dump_call_end_locked();
382    pipe_mutex_unlock(call_mutex);
383 }
384
385 void trace_dump_arg_begin(const char *name)
386 {
387    if (!dumping)
388       return;
389
390    trace_dump_indent(2);
391    trace_dump_tag_begin1("arg", "name", name);
392 }
393
394 void trace_dump_arg_end(void)
395 {
396    if (!dumping)
397       return;
398
399    trace_dump_tag_end("arg");
400    trace_dump_newline();
401 }
402
403 void trace_dump_ret_begin(void)
404 {
405    if (!dumping)
406       return;
407
408    trace_dump_indent(2);
409    trace_dump_tag_begin("ret");
410 }
411
412 void trace_dump_ret_end(void)
413 {
414    if (!dumping)
415       return;
416
417    trace_dump_tag_end("ret");
418    trace_dump_newline();
419 }
420
421 void trace_dump_bool(int value)
422 {
423    if (!dumping)
424       return;
425
426    trace_dump_writef("<bool>%c</bool>", value ? '1' : '0');
427 }
428
429 void trace_dump_int(long long int value)
430 {
431    if (!dumping)
432       return;
433
434    trace_dump_writef("<int>%lli</int>", value);
435 }
436
437 void trace_dump_uint(long long unsigned value)
438 {
439    if (!dumping)
440       return;
441
442    trace_dump_writef("<uint>%llu</uint>", value);
443 }
444
445 void trace_dump_float(double value)
446 {
447    if (!dumping)
448       return;
449
450    trace_dump_writef("<float>%g</float>", value);
451 }
452
453 void trace_dump_bytes(const void *data,
454                       size_t size)
455 {
456    static const char hex_table[16] = "0123456789ABCDEF";
457    const uint8_t *p = data;
458    size_t i;
459
460    if (!dumping)
461       return;
462
463    trace_dump_writes("<bytes>");
464    for(i = 0; i < size; ++i) {
465       uint8_t byte = *p++;
466       char hex[2];
467       hex[0] = hex_table[byte >> 4];
468       hex[1] = hex_table[byte & 0xf];
469       trace_dump_write(hex, 2);
470    }
471    trace_dump_writes("</bytes>");
472 }
473
474 void trace_dump_string(const char *str)
475 {
476    if (!dumping)
477       return;
478
479    trace_dump_writes("<string>");
480    trace_dump_escape(str);
481    trace_dump_writes("</string>");
482 }
483
484 void trace_dump_enum(const char *value)
485 {
486    if (!dumping)
487       return;
488
489    trace_dump_writes("<enum>");
490    trace_dump_escape(value);
491    trace_dump_writes("</enum>");
492 }
493
494 void trace_dump_array_begin(void)
495 {
496    if (!dumping)
497       return;
498
499    trace_dump_writes("<array>");
500 }
501
502 void trace_dump_array_end(void)
503 {
504    if (!dumping)
505       return;
506
507    trace_dump_writes("</array>");
508 }
509
510 void trace_dump_elem_begin(void)
511 {
512    if (!dumping)
513       return;
514
515    trace_dump_writes("<elem>");
516 }
517
518 void trace_dump_elem_end(void)
519 {
520    if (!dumping)
521       return;
522
523    trace_dump_writes("</elem>");
524 }
525
526 void trace_dump_struct_begin(const char *name)
527 {
528    if (!dumping)
529       return;
530
531    trace_dump_writef("<struct name='%s'>", name);
532 }
533
534 void trace_dump_struct_end(void)
535 {
536    if (!dumping)
537       return;
538
539    trace_dump_writes("</struct>");
540 }
541
542 void trace_dump_member_begin(const char *name)
543 {
544    if (!dumping)
545       return;
546
547    trace_dump_writef("<member name='%s'>", name);
548 }
549
550 void trace_dump_member_end(void)
551 {
552    if (!dumping)
553       return;
554
555    trace_dump_writes("</member>");
556 }
557
558 void trace_dump_null(void)
559 {
560    if (!dumping)
561       return;
562
563    trace_dump_writes("<null/>");
564 }
565
566 void trace_dump_ptr(const void *value)
567 {
568    if (!dumping)
569       return;
570
571    if(value)
572       trace_dump_writef("<ptr>0x%08lx</ptr>", (unsigned long)(uintptr_t)value);
573    else
574       trace_dump_null();
575 }
576
577 void trace_dump_buffer_ptr(struct pipe_buffer *_buffer)
578 {
579    if (!dumping)
580       return;
581
582    if (_buffer) {
583       struct trace_buffer *tr_buf = trace_buffer(_buffer);
584       trace_dump_ptr(tr_buf->buffer);
585    } else {
586       trace_dump_null();
587    }
588 }
589
590 void trace_dump_texture_ptr(struct pipe_texture *_texture)
591 {
592    if (!dumping)
593       return;
594
595    if (_texture) {
596       struct trace_texture *tr_tex = trace_texture(_texture);
597       trace_dump_ptr(tr_tex->texture);
598    } else {
599       trace_dump_null();
600    }
601 }
602
603 void trace_dump_surface_ptr(struct pipe_surface *_surface)
604 {
605    if (!dumping)
606       return;
607
608    if (_surface) {
609       struct trace_surface *tr_surf = trace_surface(_surface);
610       trace_dump_ptr(tr_surf->surface);
611    } else {
612       trace_dump_null();
613    }
614 }
615
616 void trace_dump_transfer_ptr(struct pipe_transfer *_transfer)
617 {
618    if (!dumping)
619       return;
620
621    if (_transfer) {
622       struct trace_transfer *tr_tran = trace_transfer(_transfer);
623       trace_dump_ptr(tr_tran->transfer);
624    } else {
625       trace_dump_null();
626    }
627 }