better performance feedback
[vg.git] / src / vg / vg_profiler.h
1 #ifndef VG_PROFILER_H
2 #define VG_PROFILER_H
3
4 #include <alloca.h>
5 #include "vg_platform.h"
6
7 #define VG_PROFILE_SAMPLE_COUNT 128
8
9 static int vg_profiler = 0;
10
11 struct vg_profile
12 {
13 const char *name;
14
15 float samples[ VG_PROFILE_SAMPLE_COUNT ];
16 u32 buffer_count, buffer_current;
17
18 enum profile_mode
19 {
20 k_profile_mode_frame,
21 k_profile_mode_accum
22 }
23 mode;
24
25 struct timespec start;
26 };
27
28 static void vg_profile_begin( struct vg_profile *profile )
29 {
30 clock_gettime( CLOCK_REALTIME, &profile->start );
31 }
32
33 static void vg_profile_increment( struct vg_profile *profile )
34 {
35 profile->buffer_current ++;
36
37 if( profile->buffer_count < VG_PROFILE_SAMPLE_COUNT )
38 profile->buffer_count ++;
39
40 if( profile->buffer_current >= VG_PROFILE_SAMPLE_COUNT )
41 profile->buffer_current = 0;
42
43 profile->samples[ profile->buffer_current ] = 0.0f;
44 }
45
46 static void vg_profile_end( struct vg_profile *profile )
47 {
48 struct timespec time_end;
49
50 clock_gettime( CLOCK_REALTIME, &time_end );
51 float delta = vg_time_diff( profile->start, time_end );
52
53
54 if( profile->mode == k_profile_mode_frame )
55 {
56 profile->samples[ profile->buffer_current ] = delta;
57 vg_profile_increment( profile );
58 }
59 else
60 {
61 profile->samples[ profile->buffer_current ] += delta;
62 }
63 }
64
65 static void vg_profile_drawn( struct vg_profile **profiles, u32 count,
66 float budget, ui_rect panel, u32 colour_offset )
67 {
68 if( !vg_profiler )
69 return;
70
71 if( panel[2] == 0 )
72 panel[2] = 256;
73
74 if( panel[3] == 0 )
75 panel[3] = VG_PROFILE_SAMPLE_COUNT * 2;
76
77 float sh = panel[3] / VG_PROFILE_SAMPLE_COUNT,
78 sw = panel[2];
79
80 float *avgs = alloca( count * sizeof(float) );
81 int *ptrs = alloca( count * sizeof(int) );
82
83 for( int i=0; i<count; i++ )
84 {
85 ptrs[i] = profiles[i]->buffer_current;
86 avgs[i] = 0.0f;
87 }
88
89 u32 colours[] = { 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000,
90 0xffff00ff, 0xffffff00 };
91
92 for( int i=0; i<VG_PROFILE_SAMPLE_COUNT-1; i++ )
93 {
94 float total = 0.0f;
95
96 for( int j=0; j<count; j++ )
97 {
98 ptrs[j] --;
99
100 if( ptrs[j] < 0 )
101 ptrs[j] = VG_PROFILE_SAMPLE_COUNT-1;
102
103 float sample = profiles[j]->samples[ptrs[j]],
104 px = (total / (budget*0.25f)) * sw,
105 wx = (sample / (budget*0.25f)) * sw;
106
107 ui_rect block = { panel[0] + px, panel[1] + (float)i*sh,
108 wx, sh };
109
110 u32 colour = colours[ (j+colour_offset) % vg_list_size(colours) ];
111 ui_fill_rect( &ui_global_ctx, block, colour );
112
113 total += sample;
114 avgs[j] += sample;
115 }
116 }
117
118 char infbuf[64];
119
120 for( int i=0; i<count; i++ )
121 {
122 snprintf( infbuf, 64, "%.1fms %s",
123 avgs[i] * (1.0f/(VG_PROFILE_SAMPLE_COUNT-1)),
124 profiles[i]->name );
125
126 ui_text( &ui_global_ctx, (ui_rect){ panel[0] + panel[2] + 4,
127 panel[1] + i * 14, 0, 0 },
128 infbuf,
129 1,
130 k_text_align_left );
131 }
132 }
133
134 static void vg_profiler_init(void)
135 {
136 vg_convar_push( (struct vg_convar){
137 .name = "vg_profiler",
138 .data = &vg_profiler,
139 .data_type = k_convar_dtype_i32,
140 .opt_i32 = { .min=0, .max=1, .clamp=1 },
141 .persistent = 1
142 });
143 }
144
145 #endif /* VG_PROFILER_H */