+#ifndef VG_PROFILER_H
+#define VG_PROFILER_H
+
+#include <alloca.h>
+#include "vg_platform.h"
+
+#define VG_PROFILE_SAMPLE_COUNT 128
+
+static int vg_profiler = 0;
+
+struct vg_profile
+{
+ const char *name;
+
+ float samples[ VG_PROFILE_SAMPLE_COUNT ];
+ u32 buffer_count, buffer_current;
+
+ enum profile_mode
+ {
+ k_profile_mode_frame,
+ k_profile_mode_accum
+ }
+ mode;
+
+ struct timespec start;
+};
+
+static void vg_profile_begin( struct vg_profile *profile )
+{
+ clock_gettime( CLOCK_REALTIME, &profile->start );
+}
+
+static void vg_profile_increment( struct vg_profile *profile )
+{
+ profile->buffer_current ++;
+
+ if( profile->buffer_count < VG_PROFILE_SAMPLE_COUNT )
+ profile->buffer_count ++;
+
+ if( profile->buffer_current >= VG_PROFILE_SAMPLE_COUNT )
+ profile->buffer_current = 0;
+
+ profile->samples[ profile->buffer_current ] = 0.0f;
+}
+
+static void vg_profile_end( struct vg_profile *profile )
+{
+ struct timespec time_end;
+
+ clock_gettime( CLOCK_REALTIME, &time_end );
+ float delta = vg_time_diff( profile->start, time_end );
+
+
+ if( profile->mode == k_profile_mode_frame )
+ {
+ profile->samples[ profile->buffer_current ] = delta;
+ vg_profile_increment( profile );
+ }
+ else
+ {
+ profile->samples[ profile->buffer_current ] += delta;
+ }
+}
+
+static void vg_profile_drawn( struct vg_profile **profiles, u32 count,
+ float budget, ui_rect panel, u32 colour_offset )
+{
+ if( !vg_profiler )
+ return;
+
+ if( panel[2] == 0 )
+ panel[2] = 256;
+
+ if( panel[3] == 0 )
+ panel[3] = VG_PROFILE_SAMPLE_COUNT * 2;
+
+ float sh = panel[3] / VG_PROFILE_SAMPLE_COUNT,
+ sw = panel[2];
+
+ float *avgs = alloca( count * sizeof(float) );
+ int *ptrs = alloca( count * sizeof(int) );
+
+ for( int i=0; i<count; i++ )
+ {
+ ptrs[i] = profiles[i]->buffer_current;
+ avgs[i] = 0.0f;
+ }
+
+ u32 colours[] = { 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000,
+ 0xffff00ff, 0xffffff00 };
+
+ for( int i=0; i<VG_PROFILE_SAMPLE_COUNT-1; i++ )
+ {
+ float total = 0.0f;
+
+ for( int j=0; j<count; j++ )
+ {
+ ptrs[j] --;
+
+ if( ptrs[j] < 0 )
+ ptrs[j] = VG_PROFILE_SAMPLE_COUNT-1;
+
+ float sample = profiles[j]->samples[ptrs[j]],
+ px = (total / (budget*0.25f)) * sw,
+ wx = (sample / (budget*0.25f)) * sw;
+
+ ui_rect block = { panel[0] + px, panel[1] + (float)i*sh,
+ wx, sh };
+
+ u32 colour = colours[ (j+colour_offset) % vg_list_size(colours) ];
+ ui_fill_rect( &ui_global_ctx, block, colour );
+
+ total += sample;
+ avgs[j] += sample;
+ }
+ }
+
+ char infbuf[64];
+
+ for( int i=0; i<count; i++ )
+ {
+ snprintf( infbuf, 64, "%.1fms %s",
+ avgs[i] * (1.0f/(VG_PROFILE_SAMPLE_COUNT-1)),
+ profiles[i]->name );
+
+ ui_text( &ui_global_ctx, (ui_rect){ panel[0] + panel[2] + 4,
+ panel[1] + i * 14, 0, 0 },
+ infbuf,
+ 1,
+ k_text_align_left );
+ }
+}
+
+static void vg_profiler_init(void)
+{
+ vg_convar_push( (struct vg_convar){
+ .name = "vg_profiler",
+ .data = &vg_profiler,
+ .data_type = k_convar_dtype_i32,
+ .opt_i32 = { .min=0, .max=1, .clamp=1 },
+ .persistent = 1
+ });
+}
+
+#endif /* VG_PROFILER_H */