better performance feedback
authorhgn <hgodden00@gmail.com>
Sun, 9 Oct 2022 03:46:55 +0000 (04:46 +0100)
committerhgn <hgodden00@gmail.com>
Sun, 9 Oct 2022 03:46:55 +0000 (04:46 +0100)
src/vg/vg.h
src/vg/vg_audio.h
src/vg/vg_input.h
src/vg/vg_loader.h
src/vg/vg_log.h
src/vg/vg_profiler.h [new file with mode: 0644]
src/vg/vg_ui.h

index f3ed6991690edd23e57b12697a910e2b5ebe557d..4aec2496cdd0024caaa76f9f5546e698c969d932 100644 (file)
@@ -41,20 +41,6 @@ void vg_register_exit( void( *funcptr )(void), const char *name );
 
 #ifndef VG_NON_CLIENT
 
-m4x4f vg_pv;
-
-int vg_window_x = 0;
-int vg_window_y = 0;
-int vg_samples = 0;
-
-v2f vg_mouse;
-v2f vg_mouse_wheel;
-v3f vg_mouse_ws;
-
-double vg_time,
-       vg_time_last,
-       vg_time_delta;
-
 struct vg
 {
    /* Engine sync */
@@ -76,9 +62,38 @@ struct vg
    }
    engine_status;
    const char *str_const_engine_err;
-
    int          is_loaded;
 
+   /* Window information */
+   int window_x,
+       window_y,
+       samples;
+   float refresh_rate;
+
+   v2f mouse,
+       mouse_wheel;
+
+   /* Runtime */
+   double time,
+          time_last,
+          time_delta,
+          accumulator;
+
+   int fixed_iterations;
+
+   enum engine_stage
+   {
+      k_engine_stage_none,
+      k_engine_stage_update,
+      k_engine_stage_update_fixed,
+      k_engine_stage_rendering,
+      k_engine_stage_ui
+   }
+   engine_stage;
+
+   /* graphics */
+   m4x4f pv;
+
    /* Gamepad */
    GLFWgamepadstate  gamepad;
    int                               gamepad_ready;
@@ -242,21 +257,30 @@ static void vg_checkgl( const char *src_info );
 #define VG_STRINGIT( X ) #X
 #define VG_CHECK_GL_ERR() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) )
 
+#include "vg_console.h"
+#include "vg_profiler.h"
 #include "vg_audio.h"
 #include "vg_shader.h"
 #include "vg_tex.h"
 #include "vg_input.h"
 #include "vg_ui.h"
-#include "vg_console.h"
 #include "vg_lines.h"
 #include "vg_debug.h"
 #include "vg_loader.h"
 #include "vg_opt.h"
 
+/* Diagnostic */
+static struct vg_profile vg_prof_update = {.name="update()"},
+                         vg_prof_render = {.name="render()"};
+
 #define VG_GAMELOOP
 static void vg_register(void) VG_GAMELOOP;
 static void vg_start(void) VG_GAMELOOP;
+
 static void vg_update(int loaded) VG_GAMELOOP;
+static void vg_update_fixed(int loaded) VG_GAMELOOP;
+static void vg_update_post(int loaded) VG_GAMELOOP;
+
 static void vg_framebuffer_resize(int w, int h) VG_GAMELOOP;
 static void vg_render(void) VG_GAMELOOP;
 static void vg_ui(void) VG_GAMELOOP;
@@ -278,14 +302,14 @@ static void vg_checkgl( const char *src_info )
 
 void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos )
 {
-   vg_mouse[0] = xpos;
-   vg_mouse[1] = ypos;
+   vg.mouse[0] = xpos;
+   vg.mouse[1] = ypos;
 }
 
 void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset )
 {
-   vg_mouse_wheel[0] += xoffset;
-   vg_mouse_wheel[1] += yoffset;
+   vg.mouse_wheel[0] += xoffset;
+   vg.mouse_wheel[1] += yoffset;
 }
 
 void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h )
@@ -296,8 +320,8 @@ void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h )
       return;
    }
 
-   vg_window_x = w;
-   vg_window_y = h;
+   vg.window_x = w;
+   vg.window_y = h;
 
    vg_framebuffer_resize(w,h);
 }
@@ -330,6 +354,7 @@ static void vg_load_full(void)
    vg_loader_highwater( vg_gamepad_init, NULL, NULL );
    vg_loader_highwater( vg_lines_init, vg_lines_free, NULL );
    vg_loader_highwater( vg_audio_init, vg_audio_free, NULL );
+   vg_loader_highwater( vg_profiler_init, NULL, NULL );
 
    /* client */
    vg_load();
@@ -346,17 +371,17 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    {
       if( (arg = vg_opt_arg( 'w' )) )
       {
-         vg_window_x = atoi( arg );
+         vg.window_x = atoi( arg );
       }
 
       if( (arg = vg_opt_arg( 'h' )) )
       {
-         vg_window_y = atoi( arg );
+         vg.window_y = atoi( arg );
       }
 
       if( (arg = vg_long_opt_arg( "samples" )) )
       {
-         vg_samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
+         vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
       }
    }
 
@@ -373,7 +398,7 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE );
    glfwWindowHint( GLFW_DOUBLEBUFFER, GLFW_TRUE );
    
-   glfwWindowHint( GLFW_SAMPLES, vg_samples );
+   glfwWindowHint( GLFW_SAMPLES, vg.samples );
    
    GLFWmonitor *monitor_primary = glfwGetPrimaryMonitor();
    
@@ -382,21 +407,21 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    glfwWindowHint( GLFW_GREEN_BITS, mode->greenBits );
    glfwWindowHint( GLFW_BLUE_BITS, mode->blueBits );
 
-   /* TODO? */
-   glfwWindowHint( GLFW_REFRESH_RATE, 60 );
+   glfwWindowHint( GLFW_REFRESH_RATE, mode->refreshRate );
 
-   if( !vg_window_x )
-      vg_window_x = mode->width;
+   if( !vg.window_x )
+      vg.window_x = mode->width;
 
-   if( !vg_window_y )
-      vg_window_y = mode->height;
+   if( !vg.window_y )
+      vg.window_y = mode->height;
 
+   vg.refresh_rate = mode->refreshRate;
 
-   if( (vg.window = glfwCreateWindow(  vg_window_x, vg_window_y,
+   if( (vg.window = glfwCreateWindow(  vg.window_x, vg.window_y,
                                        window_name, monitor_primary, NULL)) )
    {
-      glfwGetFramebufferSize( vg.window, &vg_window_x, &vg_window_y );
-      vg_success( "Window created (%dx%d)\n", vg_window_x, vg_window_y );
+      glfwGetFramebufferSize( vg.window, &vg.window_x, &vg.window_y );
+      vg_success( "Window created (%dx%d)\n", vg.window_x, vg.window_y );
    }
    else
    {
@@ -462,22 +487,21 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    vg_loader_start();
 
    int loaded = 0;
-   int counter =0;
    while(1)
    {
       if( glfwWindowShouldClose( vg.window ) )
          break;
 
-      v2_copy( (v2f){ 0.0f, 0.0f }, vg_mouse_wheel );
+      v2_copy( (v2f){ 0.0f, 0.0f }, vg.mouse_wheel );
       glfwPollEvents();
 
-      vg_time_last = vg_time;
-      vg_time = glfwGetTime();
-      vg_time_delta = vg_minf( vg_time - vg_time_last, 0.1f );
+      vg.time_last = vg.time;
+      vg.time = glfwGetTime();
+      vg.time_delta = vg.time-vg.time_last;
       
       if( vg.is_loaded )
       {
-         glClearColor( 0.0f,sinf(vg_time*20.0)*0.5f+0.5f,0.0f,1.0f );
+         glClearColor( 0.0f,sinf(vg.time*20.0)*0.5f+0.5f,0.0f,1.0f );
          glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
          
          if( !loaded )
@@ -491,27 +515,65 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
          vg_loader_render();
       }
 
+      /* 
+       * Game logic 
+       * -------------------------------------------------------
+       */
+      vg_profile_begin( &vg_prof_update );
       vg_update_inputs();
+
+      vg.engine_stage = k_engine_stage_update;
       vg_update( loaded );
 
-      counter ++;
+      /* Fixed update loop */
+      vg.engine_stage = k_engine_stage_update_fixed;
+      vg.accumulator += vg.time_delta;
 
-#if 0
-      if( counter == 30 )
-         vg_fatal_exit_loop( "Test crash from main, while loading (-O0)" );
-#endif
+      vg.fixed_iterations = 0;
+      while( vg.accumulator >= (VG_TIMESTEP_FIXED-0.00125) )
+      {
+         vg_update_fixed( loaded );
+
+         vg.accumulator -= VG_TIMESTEP_FIXED;
+         vg.accumulator  = VG_MAX( 0.0, vg.accumulator );
+
+         vg.fixed_iterations ++;
+         if( vg.fixed_iterations == 8 )
+         {
+            break;
+         }
+      }
+
+      /* 
+       * Rendering 
+       * ---------------------------------------------
+       */
+      vg.engine_stage = k_engine_stage_update;
+      vg_update_post( loaded );
+      vg_profile_end( &vg_prof_update );
+
+      vg_profile_begin( &vg_prof_render );
 
       if( loaded )
       {
+         /* render */
+         vg.engine_stage = k_engine_stage_rendering;
          vg_render();
 
          /* ui */
+         vg.engine_stage = k_engine_stage_ui;
          {
-            ui_begin( &ui_global_ctx, vg_window_x, vg_window_y );
-            ui_set_mouse( &ui_global_ctx, vg_mouse[0], vg_mouse[1], 
+            ui_begin( &ui_global_ctx, vg.window_x, vg.window_y );
+            ui_set_mouse( &ui_global_ctx, vg.mouse[0], vg.mouse[1], 
                   vg_get_button_state( "primary" ) );
             
-            audio_debug_ui( vg_pv );
+            vg_profile_drawn( 
+                  (struct vg_profile *[]){&vg_prof_update,&vg_prof_render}, 2,
+                  (1.0f/(float)vg.refresh_rate)*1000.0f, 
+                  (ui_rect){ 4, 4, 250, 0 }, 0
+            );
+
+            audio_debug_ui( vg.pv );
             vg_ui();
             vg_console_draw();
             
@@ -520,6 +582,8 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
          }
       }
 
+      vg_profile_end( &vg_prof_render );
+
       glfwSwapBuffers( vg.window );
       vg_run_synced_content();
    }
@@ -542,6 +606,11 @@ il_exit_ui:
 /*
  * Immediately transfer away from calling thread into a safe loop, signal for 
  * others to shutdown, then free everything once the user closes the window.
+ *
+ * FIXME(bug): glfwWindowShouldClose() never returns 1 in windows via wine, only
+ *             when calling the program from outside its normal directory.
+ *
+ *             A workaround is placed to skip the error loop on windows builds
  */
 static void vg_fatal_exit_loop( const char *error )
 {
@@ -595,24 +664,29 @@ static void vg_fatal_exit_loop( const char *error )
       }
       vg_audio_free(NULL);
 
-      /*
-       * todo: draw error loop
-       */
+#ifndef _WIN32
       while(1)
       {
          if( glfwWindowShouldClose( vg.window ) )
             break;
 
          glfwPollEvents();
+         
+         glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+         glEnable(GL_BLEND);
+         glDisable(GL_DEPTH_TEST);
+         glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
+         glBlendEquation(GL_FUNC_ADD);
 
          glClearColor( 0.15f + sinf(glfwGetTime())*0.1f, 0.0f, 0.0f,1.0f );
          glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
-         glViewport( 0,0, vg_window_x, vg_window_y );
+         glViewport( 0,0, vg.window_x, vg.window_y );
 
          vg_render_log();
 
          glfwSwapBuffers( vg.window );
       }
+#endif
 
       /* Can now shutdown and EXIT */
       vg_loader_free();
index ae37b2e5078000476f2d2f879fbec4d872817609..9ed6cda66918322acb3c481c0b29af11172b2194 100644 (file)
@@ -122,6 +122,7 @@ static struct vg_audio_system
    void             *mem, *decode_mem;
    u32               mem_current,
                      mem_total;
+   u32               samples_last;
 
    /* synchro */
    int               sync_locked;
@@ -150,23 +151,21 @@ static struct vg_audio_system
    /* System queue, and access from thread 0 */
    audio_entity      entity_queue[SFX_MAX_SYSTEMS];
    int               queue_len;
-
-   char              performance_info[128],
-                     performance_sub0[64],
-                     performance_sub1[64];
-
    int               debug_ui;
 
    v3f               listener_pos,
                      listener_ears;
-
-   double            perf_ms_decode,
-                     perf_ms_mix;
-
-   u32               perf_measurements;
 }
 vg_audio;
 
+static struct vg_profile 
+   _vg_prof_audio_decode = {.mode = k_profile_mode_accum,
+                            .name = "[T2] audio_decode()"},
+   _vg_prof_audio_mix    = {.mode = k_profile_mode_accum,
+                            .name = "[T2] audio_mix()"},
+   vg_prof_audio_decode,
+   vg_prof_audio_mix;
+
 static void *audio_alloc( u32 size )
 {
    u32 new_current = vg_audio.mem_current + size;
@@ -559,8 +558,7 @@ stb_vorbis_get_samples_float_interleaved_stereo( stb_vorbis *f, float *buffer,
 
 static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf )
 {
-   struct timespec time_start, time_end;
-   clock_gettime( CLOCK_REALTIME, &time_start );
+   vg_profile_begin( &_vg_prof_audio_decode );
 
    struct active_audio_player *aap = &vg_audio.active_players[id];
    audio_entity *ent = &aap->ent;
@@ -623,9 +621,7 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf )
    }
 
    ent->cur = cursor;
-
-   clock_gettime( CLOCK_REALTIME, &time_end );
-   vg_audio.perf_ms_decode += vg_time_diff( time_start, time_end );
+   vg_profile_end( &_vg_prof_audio_decode );
 }
 
 static void audio_entity_mix( aatree_ptr id, float *buffer, 
@@ -644,8 +640,7 @@ static void audio_entity_mix( aatree_ptr id, float *buffer,
 
    audio_entity_get_samples( id, frame_count, pcf );
 
-   struct timespec time_start, time_end;
-   clock_gettime( CLOCK_REALTIME, &time_start );
+   vg_profile_begin( &_vg_prof_audio_mix );
 
    if( ent->info.flags & AUDIO_FLAG_SPACIAL_3D )
       audio_entity_spacialize( ent, &vol, &pan );
@@ -677,8 +672,7 @@ static void audio_entity_mix( aatree_ptr id, float *buffer,
       buffer_pos ++;
    }
 
-   clock_gettime( CLOCK_REALTIME, &time_end );
-   vg_audio.perf_ms_mix += vg_time_diff( time_start, time_end );
+   vg_profile_end( &_vg_prof_audio_mix );
 }
 
 /*
@@ -707,10 +701,6 @@ static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf,
          audio_entity_mix( i, pOut32F, frame_count );
       }
    }
-   
-#if 0
-   vg_sleep_ms( 20 );
-#endif
 
    /* redistribute */
    audio_system_cleanup();
@@ -718,33 +708,16 @@ static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf,
    /* TODO: what the hell is this? */
    (void)pInput;
    
-   /*
-    * Debug information
-    */
-   clock_gettime( CLOCK_REALTIME, &time_end );
-
-   double elapsed = vg_time_diff( time_start, time_end ),
-          budget  = ((double)frame_count / 44100.0) * 1000.0,
-          percent = (elapsed/budget) * 100.0;
-
-   snprintf( vg_audio.performance_info, 127, 
-                  "%.2fms/%.2fms (%.1f%%) (%u frames)",
-                  elapsed, budget, percent, frame_count );
 
-   vg_audio.perf_measurements ++;
-   if( vg_audio.perf_measurements >= 30 )
-   {
-      double ms_decode = vg_audio.perf_ms_decode * (1.0/30.0),
-             ms_mix    = vg_audio.perf_ms_mix    * (1.0/30.0);
-      
-      snprintf( vg_audio.performance_sub0, 63, "Decode %.2fms", ms_decode );
-      snprintf( vg_audio.performance_sub1, 63, "mix    %.2fms", ms_mix );
+   audio_lock();
+   vg_profile_increment( &_vg_prof_audio_decode );
+   vg_profile_increment( &_vg_prof_audio_mix );
 
-      vg_audio.perf_ms_decode = 0.0;
-      vg_audio.perf_ms_mix = 0.0;
+   vg_prof_audio_mix = _vg_prof_audio_mix;
+   vg_prof_audio_decode = _vg_prof_audio_decode;
 
-      vg_audio.perf_measurements = 0;
-   }
+   vg_audio.samples_last = frame_count;
+   audio_unlock();
 }
 
 /* Decompress entire vorbis stream into buffer */
@@ -1013,10 +986,6 @@ static void audio_debug_ui( m4x4f mtx_pv )
        infos[ SFX_MAX_SYSTEMS ];
        int num_systems = 0;
 
-   char perf[128],
-        psub0[64],
-        psub1[64];
-       
    audio_lock();
        
        for( int i=0; i<SFX_MAX_SYSTEMS; i ++ )
@@ -1036,26 +1005,22 @@ static void audio_debug_ui( m4x4f mtx_pv )
       snd->vol = ent->info.vol*100.0f;
       v3_copy( ent->info.world_position, snd->pos );
        }
-   strcpy( perf, vg_audio.performance_info );
-   strcpy( psub0, vg_audio.performance_sub0 );
-   strcpy( psub1, vg_audio.performance_sub1 );
+
+   float budget = ((double)vg_audio.samples_last / 44100.0) * 1000.0;
+   vg_profile_drawn( (struct vg_profile *[]){ &vg_prof_audio_decode,
+                                              &vg_prof_audio_mix }, 2, 
+                     budget, (ui_rect){ 4, VG_PROFILE_SAMPLE_COUNT*2 + 8,
+                                        250, 0 }, 3 );
 
    audio_unlock();
 
+   char perf[128];
+       
    /* Draw UI */
-   ui_global_ctx.cursor[0] = 10;
-   ui_global_ctx.cursor[1] = 10;
+   ui_global_ctx.cursor[0] = 258;
+   ui_global_ctx.cursor[1] = VG_PROFILE_SAMPLE_COUNT*2+8+24+12;
    ui_global_ctx.cursor[2] = 150;
    ui_global_ctx.cursor[3] = 12;
-
-   ui_text( &ui_global_ctx, ui_global_ctx.cursor, perf, 1, 0 );
-   ui_global_ctx.cursor[1] += 20;
-
-   ui_text( &ui_global_ctx, ui_global_ctx.cursor, psub0, 1, 0 );
-   ui_global_ctx.cursor[1] += 20;
-
-   ui_text( &ui_global_ctx, ui_global_ctx.cursor, psub1, 1, 0 );
-   ui_global_ctx.cursor[1] += 20;
    
    float usage = (float)vg_audio.mem_current / (1024.0f*1024.0f),
          total = (float)vg_audio.mem_total   / (1024.0f*1024.0f),
@@ -1110,8 +1075,8 @@ static void audio_debug_ui( m4x4f mtx_pv )
             v2_add( wpos, (v2f){ 0.5f, 0.5f }, wpos );
             
             ui_rect wr;
-            wr[0] = wpos[0] * vg_window_x;
-            wr[1] = (1.0f-wpos[1]) * vg_window_y;
+            wr[0] = wpos[0] * vg.window_x;
+            wr[1] = (1.0f-wpos[1]) * vg.window_y;
             wr[2] = 100;
             wr[3] = 17;
             
index c33853136ceb01e15dd8ff94dbd7c383ddd8eff6..1cbc19371398cf8f9374ab9f152c4f239491db1f 100644 (file)
@@ -7,6 +7,10 @@
 
 static inline float vg_get_axis( const char *axis );
 static inline int vg_get_button( const char *button );
+
+/*
+ * Cannot be used in fixed update
+ */
 static inline int vg_get_button_down( const char *button );
 static inline int vg_get_button_up( const char *button );
 
@@ -113,6 +117,9 @@ static inline int vg_get_button( const char *button )
 
 static inline int vg_get_button_down( const char *button )
 {
+   if( vg.engine_stage == k_engine_stage_update_fixed )
+      vg_fatal_exit_loop( "Cannot use that here\n" );
+
    int cur, prev;
    vg_get_button_states( button, &cur, &prev );
 
@@ -121,6 +128,9 @@ static inline int vg_get_button_down( const char *button )
 
 static inline int vg_get_button_up( const char *button )
 {
+   if( vg.engine_stage == k_engine_stage_update_fixed )
+      vg_fatal_exit_loop( "Cannot use that here\n" );
+
    int cur, prev;
    vg_get_button_states( button, &cur, &prev );
 
index 7245a29d88467eb91f1c076da6bf8c04afe073a8..c7522b0addb811e3695be881d955149587bcfdb2 100644 (file)
@@ -123,11 +123,10 @@ static float hue_to_rgb( float p, float q, float t )
 
 static void vg_render_log(void)
 {
-   ui_begin( &ui_global_ctx, vg_window_x, vg_window_y );
-
+   ui_begin( &ui_global_ctx, vg.window_x, vg.window_y );
 
    int const fh = 14;
-   int lines_screen_max = ((vg_window_y/fh)-2),
+   int lines_screen_max = ((vg.window_y/fh)-2),
        lines_max_draw = VG_MIN( lines_screen_max, vg_list_size(vg_log.buffer) ),
        lines_to_draw  = VG_MIN( lines_max_draw, vg_log.buffer_line_count );
 
@@ -157,13 +156,13 @@ static void vg_render_log(void)
 
 static void vg_loader_render(void)
 {
-   glViewport( 0,0, vg_window_x, vg_window_y );
+   glViewport( 0,0, vg.window_x, vg.window_y );
    glBindFramebuffer( GL_FRAMEBUFFER, 0 );
    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
 
    glUseProgram( _shader_loader.id );
-       glUniform1f( glGetUniformLocation( _shader_loader.id, "uTime" ), vg_time );
+       glUniform1f( glGetUniformLocation( _shader_loader.id, "uTime" ), vg.time );
 
    glBindVertexArray( vg_loader.vao );
    glDrawArrays( GL_TRIANGLES, 0, 6 );
index 54ee188c3df95ffdb6f388ca2d6a50ae68c62219..28713318104dc3917ba590beb838e04065e3afdf 100644 (file)
@@ -55,7 +55,7 @@ static void vg_log_write( FILE *file, const char *prefix,
        char buffer[512];
        int i, j;
        
-       for( i = 0; i < vg_list_size( buffer ); i ++ )
+       for( i=0; i<vg_list_size( buffer ); i ++ )
        {
                if( prefix[i] )
                        buffer[i] = prefix[i];
diff --git a/src/vg/vg_profiler.h b/src/vg/vg_profiler.h
new file mode 100644 (file)
index 0000000..6c9530c
--- /dev/null
@@ -0,0 +1,145 @@
+#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 */
index 4e09338dc2985149ea84f711e596433754ba37f4..0debac69adbd0a53c894375273468dd8b8f4c603 100644 (file)
@@ -354,8 +354,8 @@ static void ui_draw( ui_ctx *ctx, m3x3f view_override )
                view_override = view;
        
                m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } );
-               m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), 
-                              -1.0f/((float)vg_window_y*0.5f), 1.0f } );
+               m3x3_scale( view, (v3f){ 1.0f/((float)vg.window_x*0.5f), 
+                              -1.0f/((float)vg.window_y*0.5f), 1.0f } );
        }
        
    /* TODO? */