diff --git a/src/game/hud.c b/src/game/hud.c index ce35b8e6..f28dca43 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -666,18 +666,5 @@ void render_hud(void) { if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER && showHud) { render_hud_timer(); } - - extern bool configLuaProfiler; - if (configLuaProfiler) { - extern void lua_profiler_update_counters(); - lua_profiler_update_counters(); - } -#ifdef DEVELOPMENT - extern bool configCtxProfiler; - if (configCtxProfiler) { - extern void ctx_profiler_update_counters(); - ctx_profiler_update_counters(); - } -#endif } } diff --git a/src/pc/debug_context.c b/src/pc/debug_context.c index 9f09b748..b0727519 100644 --- a/src/pc/debug_context.c +++ b/src/pc/debug_context.c @@ -2,8 +2,6 @@ #include "utils/misc.h" #include "debug_context.h" #include "debuglog.h" -#include "game/print.h" -#include "game/hud.h" #include "gfx_dimensions.h" static u32 sCtxDepth[CTX_MAX] = { 0 }; @@ -16,20 +14,6 @@ static f64 sCtxTime[CTX_MAX] = { 0 }; static f64 sCtxStartTimeStack[MAX_TIME_STACK] = { 0 }; static u32 sCtxStackIndex = 0; -static char* sDebugContextNames[] = { - "NONE", - "FRAME", - "NET", - "INTERP", - "GAME", - "SMLUA", - "AUDIO", - "RENDER", - "LEVEL", - "HOOK", - "MAX", -}; - #endif void debug_context_begin(enum DebugContext ctx) { @@ -71,29 +55,16 @@ void debug_context_reset(void) { } bool debug_context_within(enum DebugContext ctx) { - if (ctx > CTX_MAX) { return false; } + if (ctx >= CTX_MAX) { return false; } return sCtxDepth[ctx] > 0; } -#ifdef DEVELOPMENT - -void ctx_profiler_update_counters(void) { - s32 y = SCREEN_HEIGHT - 60; - for (s32 i = 1; i < CTX_MAX; i++) { - const char *name = sDebugContextNames[i]; - s32 counterUs = (s32) (sCtxTime[i] * 1000000.0); - char text[256]; - snprintf(text, 256, " %05d", counterUs); - memcpy(text, name, MIN(12, strlen(name))); - for (s32 j = 0; j != 12; ++j) { - char c = text[j]; - if (c >= 'a' && c <= 'z') c -= ('a' - 'A'); - if ((c < '0' || c > '9') && (c < 'A' || c > 'Z')) c = ' '; - text[j] = c; - } - print_text(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(4), y, text); - y -= 18; - } +void debug_context_set_time(enum DebugContext ctx, f64 time) { + if (ctx >= CTX_MAX) { return; } + sCtxTime[ctx] = time; } -#endif \ No newline at end of file +f64 debug_context_get_time(enum DebugContext ctx) { + if (ctx >= CTX_MAX) { return 0.0; } + return sCtxTime[ctx]; +} \ No newline at end of file diff --git a/src/pc/debug_context.h b/src/pc/debug_context.h index e7dbe9c7..27048a91 100644 --- a/src/pc/debug_context.h +++ b/src/pc/debug_context.h @@ -1,15 +1,17 @@ #pragma once +#include #include #define CTX_BEGIN(_ctx) debug_context_begin(_ctx) #define CTX_END(_ctx) debug_context_end(_ctx) #define CTX_WITHIN(_ctx) debug_context_within(_ctx) +#define CTX_TIME(_ctx, time) debug_context_set_time(_ctx, time) #define CTX_EXTENT(_ctx, _f) { CTX_BEGIN(_ctx); _f(); CTX_END(_ctx); } enum DebugContext { CTX_NONE, - CTX_FRAME, + CTX_TOTAL, CTX_NETWORK, CTX_INTERP, CTX_GAME_LOOP, @@ -26,3 +28,5 @@ void debug_context_begin(enum DebugContext ctx); void debug_context_end(enum DebugContext ctx); void debug_context_reset(void); bool debug_context_within(enum DebugContext ctx); +void debug_context_set_time(enum DebugContext ctx, f64 time); +f64 debug_context_get_time(enum DebugContext ctx); \ No newline at end of file diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index b559f1f8..19d98b95 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -5,7 +5,9 @@ #include "djui_panel_pause.h" #include "djui_panel_join.h" #include "djui_panel_join_message.h" +#include "djui_ctx_display.h" #include "djui_fps_display.h" +#include "djui_lua_profiler.h" #include "../debuglog.h" #include "pc/cliopts.h" #include "game/level_update.h" @@ -52,6 +54,8 @@ void djui_shutdown(void) { } djui_fps_display_destroy(); + djui_ctx_display_destroy(); + djui_lua_profiler_destroy(); gDjuiShuttingDown = false; sDjuiInited = false; @@ -97,6 +101,8 @@ void djui_init(void) { djui_console_create(); djui_fps_display_create(); + djui_ctx_display_create(); + djui_lua_profiler_create(); sDjuiInited = true; } @@ -158,6 +164,8 @@ void djui_render(void) { } djui_fps_display_render(); + djui_ctx_display_render(); + djui_lua_profiler_render(); if (sDjuiLuaErrorTimeout > 0) { sDjuiLuaErrorTimeout--; diff --git a/src/pc/djui/djui_ctx_display.c b/src/pc/djui/djui_ctx_display.c new file mode 100644 index 00000000..4bc90017 --- /dev/null +++ b/src/pc/djui/djui_ctx_display.c @@ -0,0 +1,139 @@ +#include "djui_ctx_display.h" + +#include "djui.h" +#include "pc/pc_main.h" +#include "pc/debug_context.h" + +#ifdef DEVELOPMENT + +static char* sDebugContextNames[] = { + "NONE", + "TOTAL", + "NET", + "INTERP", + "GAME", + "SMLUA", + "AUDIO", + "RENDER", + "LEVEL", + "HOOK", + "OTHER", + "MAX", +}; + +#endif + +struct DjuiCtxEntry { + struct DjuiText *name; + struct DjuiText *timing; +}; + +struct DjuiCtxDisplay { + struct DjuiCtxEntry topEntry; + struct DjuiCtxEntry entries[CTX_MAX]; + struct DjuiBase base; +}; + + +struct DjuiCtxDisplay *sCtxDisplay = NULL; + +void djui_ctx_display_update(void) { + if (!configCtxProfiler || sCtxDisplay == NULL) { return; } + +#ifdef DEVELOPMENT + // Time we have for a indivdual frame. If we exceed it. We are in the red. + f64 frameTime = 1.0 / 30.0; + s32 frameTimeMs = (s32)(frameTime * 1000000.0); + + struct DjuiCtxEntry *topEntry = &sCtxDisplay->topEntry; + + // If we've exceeded our available frame time. Make the top entry timing red - For dramatic effect. + // Otherwise. It's green! + if (debug_context_get_time(CTX_TOTAL) > frameTime) { + djui_base_set_color(&topEntry->timing->base, 255, 69, 0, 240); + } else { + djui_base_set_color(&topEntry->timing->base, 124, 252, 0, 240); + } + + djui_text_set_text(topEntry->name, "FRAME"); + char timing[32]; + snprintf(timing, 32, "%05d", frameTimeMs); + djui_text_set_text(topEntry->timing, timing); + + // Draw the counters. + for (s32 i = CTX_TOTAL; i < CTX_MAX; i++) { + struct DjuiCtxEntry *entry = &sCtxDisplay->entries[i]; + + const char *name = sDebugContextNames[i]; + djui_text_set_text(entry->name, name); + + // The timing is in microseconds. + s32 counterMs = (s32)(debug_context_get_time(i) * 1000000.0); + char timing[32]; + snprintf(timing, 32, "%05d", counterMs); + djui_text_set_text(entry->timing, timing); + } +#endif +} + +void djui_ctx_display_render(void) { + if (!configCtxProfiler || sCtxDisplay == NULL) { return; } + + djui_rect_render(&sCtxDisplay->base); + djui_base_render(&sCtxDisplay->base); +} + +void djui_ctx_display_on_destroy(UNUSED struct DjuiBase* base) { + free(sCtxDisplay); +} + +void djui_ctx_display_initialize_entry(struct DjuiBase *base, struct DjuiCtxEntry *entry, f64 offset) { + struct DjuiText *name = djui_text_create(base, ""); + djui_text_set_alignment(name, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + djui_base_set_size_type(&name->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&name->base, 1.0f, name->fontScale * 2); + djui_base_set_location(&name->base, 0, -name->fontScale / 3.0f + offset); + djui_base_set_color(&name->base, 255, 255, 255, 240); + + struct DjuiText *timing = djui_text_create(base, ""); + djui_text_set_alignment(timing, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP); + djui_base_set_size_type(&timing->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&timing->base, 1.0f, timing->fontScale * 2); + djui_base_set_location(&timing->base, 0, -timing->fontScale / 3.0f + offset); + djui_base_set_color(&timing->base, 255, 255, 255, 240); + + entry->name = name; + entry->timing = timing; +} + +void djui_ctx_display_create(void) { + struct DjuiCtxDisplay *ctxDisplay = calloc(1, sizeof(struct DjuiCtxDisplay)); + struct DjuiBase *base = &ctxDisplay->base; + djui_base_init(NULL, base, NULL, djui_ctx_display_on_destroy); + djui_base_set_size(base, 220.0f, 39.0f + ((CTX_MAX - 2) * 26.0f)); + djui_base_set_color(base, 0, 0, 0, 240); + djui_base_set_border_color(base, 0, 0, 0, 200); + djui_base_set_border_width(base, 4); + djui_base_set_padding(base, 4, 4, 4, 4); + djui_base_set_location(base, 0, 52.0f); + + { + f64 offset = 4.0; + + djui_ctx_display_initialize_entry(base, &ctxDisplay->topEntry, offset); + offset += 35.0; + + for (s32 i = CTX_TOTAL; i < CTX_MAX; i++) { + djui_ctx_display_initialize_entry(base, &ctxDisplay->entries[i], offset); + offset += 22.0; + } + } + + sCtxDisplay = ctxDisplay; +} + +void djui_ctx_display_destroy(void) { + if (sCtxDisplay) { + djui_base_destroy(&sCtxDisplay->base); + } +} \ No newline at end of file diff --git a/src/pc/djui/djui_ctx_display.h b/src/pc/djui/djui_ctx_display.h new file mode 100644 index 00000000..ea2e28ea --- /dev/null +++ b/src/pc/djui/djui_ctx_display.h @@ -0,0 +1,7 @@ +#pragma once +#include "djui.h" + +void djui_ctx_display_update(void); +void djui_ctx_display_render(void); +void djui_ctx_display_create(void); +void djui_ctx_display_destroy(void); \ No newline at end of file diff --git a/src/pc/djui/djui_lua_profiler.c b/src/pc/djui/djui_lua_profiler.c new file mode 100644 index 00000000..e161555a --- /dev/null +++ b/src/pc/djui/djui_lua_profiler.c @@ -0,0 +1,150 @@ +#include "djui_lua_profiler.h" + +#include "djui.h" +#include "pc/pc_main.h" +#include "pc/mods/mod.h" +#include "pc/mods/mods.h" + +#define MAX_PROFILED_MODS 16 +#define REFRESH_RATE 30 + +struct DjuiPrfCounter { + f64 start; + f64 end; + f64 sum; + f64 display; +}; + +struct DjuiPrfEntry { + struct DjuiText *name; + struct DjuiText *timing; + struct DjuiPrfCounter counter; +}; + +struct DjuiPrfDisplay { + struct DjuiPrfEntry entries[MAX_PROFILED_MODS]; + struct DjuiBase base; +}; + +struct DjuiPrfDisplay *sPrfDisplay = NULL; + +void lua_profiler_start_counter(UNUSED struct Mod *mod) { + if (!configLuaProfiler || sPrfDisplay == NULL) { return; } + +#ifndef WAPI_DUMMY + for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) { + if (gActiveMods.entries[i] == mod) { + f64 freq = SDL_GetPerformanceFrequency(); + f64 curr = SDL_GetPerformanceCounter(); + sPrfDisplay->entries[i].counter.start = curr / freq; + return; + } + } +#endif +} + +void lua_profiler_stop_counter(UNUSED struct Mod *mod) { + if (!configLuaProfiler || sPrfDisplay == NULL) { return; } + +#ifndef WAPI_DUMMY + for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) { + if (gActiveMods.entries[i] == mod) { + f64 freq = SDL_GetPerformanceFrequency(); + f64 curr = SDL_GetPerformanceCounter(); + + struct DjuiPrfCounter *counter = &sPrfDisplay->entries[i].counter; + counter->end = curr / freq; + counter->sum += counter->end - counter->start; + return; + } + } +#endif +} + +void djui_lua_profiler_update(void) { + if (!configLuaProfiler || sPrfDisplay == NULL) { return; } + + // Draw the counters. + for (s32 i = 0; i < MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); i++) { + struct DjuiPrfEntry *entry = &sPrfDisplay->entries[i]; + struct DjuiPrfCounter *counter = &entry->counter; + + if (gGlobalTimer % REFRESH_RATE == 0) { + counter->display = counter->sum / (f64) REFRESH_RATE; + counter->sum = 0; + } + + char name[256]; + memset(name, 0, 256); + const char *modName = gActiveMods.entries[i]->relativePath; + memcpy(name, modName, MIN(16, strlen(modName) - (gActiveMods.entries[i]->isDirectory ? 0 : 4))); + for (s32 j = 0; j != 16; ++j) { + char c = name[j]; + if (c >= 'a' && c <= 'z') c -= ('a' - 'A'); + if ((c < '0' || c > '9') && (c < 'A' || c > 'Z')) c = ' '; + name[j] = c; + } + djui_text_set_text(entry->name, name); + + // The timing is in microseconds. + s32 counterMs = (s32)(counter->display * 1000000.0); + char timing[32]; + snprintf(timing, 32, "%05d", counterMs); + djui_text_set_text(entry->timing, timing); + } +} + +void djui_lua_profiler_render(void) { + if (!configLuaProfiler || sPrfDisplay == NULL) { return; } + + djui_rect_render(&sPrfDisplay->base); + djui_base_render(&sPrfDisplay->base); +} + +void djui_lua_profiler_on_destroy(UNUSED struct DjuiBase* base) { + free(sPrfDisplay); +} + +void djui_lua_profiler_initialize_entry(struct DjuiBase *base, struct DjuiPrfEntry *entry, f64 offset) { + struct DjuiText *name = djui_text_create(base, ""); + djui_text_set_alignment(name, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + djui_base_set_size_type(&name->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&name->base, 1.0f, name->fontScale * 2); + djui_base_set_location(&name->base, 0, -name->fontScale / 3.0f + offset); + djui_base_set_color(&name->base, 255, 255, 255, 240); + + struct DjuiText *timing = djui_text_create(base, ""); + djui_text_set_alignment(timing, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP); + djui_base_set_size_type(&timing->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&timing->base, 1.0f, timing->fontScale * 2); + djui_base_set_location(&timing->base, 0, -timing->fontScale / 3.0f + offset); + djui_base_set_color(&timing->base, 255, 255, 255, 240); + + entry->name = name; + entry->timing = timing; +} + +void djui_lua_profiler_create(void) { + struct DjuiPrfDisplay *prfDisplay = calloc(1, sizeof(struct DjuiPrfDisplay)); + struct DjuiBase *base = &prfDisplay->base; + djui_base_init(NULL, base, NULL, djui_lua_profiler_on_destroy); + djui_base_set_size(base, 290.0f, MAX_PROFILED_MODS * 26.0f); + djui_base_set_color(base, 0, 0, 0, 240); + djui_base_set_border_color(base, 0, 0, 0, 200); + djui_base_set_border_width(base, 4); + djui_base_set_padding(base, 4, 4, 4, 4); + djui_base_set_location(base, 0, 300.0f); + + f64 offset = 4.0; + for (s32 i = 0; i < MAX_PROFILED_MODS; ++i, offset += 22.0) { + djui_lua_profiler_initialize_entry(base, &prfDisplay->entries[i], offset); + } + + sPrfDisplay = prfDisplay; +} + +void djui_lua_profiler_destroy(void) { + if (sPrfDisplay) { + djui_base_destroy(&sPrfDisplay->base); + } +} \ No newline at end of file diff --git a/src/pc/djui/djui_lua_profiler.h b/src/pc/djui/djui_lua_profiler.h new file mode 100644 index 00000000..0ff5c345 --- /dev/null +++ b/src/pc/djui/djui_lua_profiler.h @@ -0,0 +1,11 @@ +#pragma once +#include "djui.h" +#include "pc/mods/mod.h" + +void lua_profiler_start_counter(UNUSED struct Mod *mod); +void lua_profiler_stop_counter(UNUSED struct Mod *mod); + +void djui_lua_profiler_update(void); +void djui_lua_profiler_render(void); +void djui_lua_profiler_create(void); +void djui_lua_profiler_destroy(void); \ No newline at end of file diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index 7725b78b..52e30a5b 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -15,6 +15,7 @@ #include "pc/network/socket/socket.h" #include "pc/chat_commands.h" #include "pc/pc_main.h" +#include "pc/djui/djui_lua_profiler.h" #include "pc/djui/djui_panel.h" #include "pc/configfile.h" @@ -22,66 +23,6 @@ #include "game/print.h" #include "gfx_dimensions.h" -#define MAX_PROFILED_MODS 16 -#define REFRESH_RATE 15 - -static struct { - f64 start; - f64 end; - f64 sum; - f64 disp; -} sLuaProfilerCounters[MAX_PROFILED_MODS]; - -static void lua_profiler_start_counter(UNUSED struct Mod *mod) { -#ifndef WAPI_DUMMY - for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) { - if (gActiveMods.entries[i] == mod) { - f64 freq = SDL_GetPerformanceFrequency(); - f64 curr = SDL_GetPerformanceCounter(); - sLuaProfilerCounters[i].start = curr / freq; - return; - } - } -#endif -} - -static void lua_profiler_stop_counter(UNUSED struct Mod *mod) { -#ifndef WAPI_DUMMY - for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) { - if (gActiveMods.entries[i] == mod) { - f64 freq = SDL_GetPerformanceFrequency(); - f64 curr = SDL_GetPerformanceCounter(); - sLuaProfilerCounters[i].end = curr / freq; - sLuaProfilerCounters[i].sum += sLuaProfilerCounters[i].end - sLuaProfilerCounters[i].start; - return; - } - } -#endif -} - -void lua_profiler_update_counters(void) { - if (gGlobalTimer % REFRESH_RATE == 0) { - for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) { - sLuaProfilerCounters[i].disp = sLuaProfilerCounters[i].sum / (f64) REFRESH_RATE; - sLuaProfilerCounters[i].sum = 0; - } - } - for (s32 i = 0, y = SCREEN_HEIGHT - 60; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i, y -= 18) { - const char *modName = gActiveMods.entries[i]->relativePath; - s32 modCounterUs = (s32) (sLuaProfilerCounters[i].disp * 1000000.0); - char text[256]; - snprintf(text, 256, " %05d", modCounterUs); - memcpy(text, modName, MIN(12, strlen(modName) - (gActiveMods.entries[i]->isDirectory ? 0 : 4))); - for (s32 j = 0; j != 12; ++j) { - char c = text[j]; - if (c >= 'a' && c <= 'z') c -= ('a' - 'A'); - if ((c < '0' || c > '9') && (c < 'A' || c > 'Z')) c = ' '; - text[j] = c; - } - print_text(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(4), y, text); - } -} - #define MAX_HOOKED_REFERENCES 64 #define LUA_BEHAVIOR_FLAG (1 << 15) @@ -102,18 +43,13 @@ int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct M gLuaActiveMod = activeMod; gLuaLastHookMod = activeMod; - extern bool configLuaProfiler; - if (configLuaProfiler) { - lua_profiler_start_counter(activeMod); - } + lua_profiler_start_counter(activeMod); CTX_BEGIN(CTX_HOOK); int rc = smlua_pcall(L, nargs, nresults, errfunc); CTX_END(CTX_HOOK); - if (configLuaProfiler) { - lua_profiler_stop_counter(activeMod); - } + lua_profiler_stop_counter(activeMod); gLuaActiveMod = prev; return rc; diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 0df94fa9..62eb0410 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,9 @@ #include "pc/djui/djui_unicode.h" #include "pc/djui/djui_panel.h" #include "pc/djui/djui_panel_modlist.h" +#include "pc/djui/djui_ctx_display.h" #include "pc/djui/djui_fps_display.h" +#include "pc/djui/djui_lua_profiler.h" #include "pc/debuglog.h" #include "pc/utils/misc.h" @@ -182,28 +185,30 @@ void produce_interpolation_frames_and_delay(void) { // interpolate and render while ((curTime = clock_elapsed_f64()) < sFrameTargetTime) { - gfx_start_frame(); f32 delta = ((!configUncappedFramerate && configFrameLimit == FRAMERATE) ? 1.0f : MAX(MIN((curTime - sFrameTimeStart) / (sFrameTargetTime - sFrameTimeStart), 1.0f), 0.0f) ); gRenderingDelta = delta; + + gfx_start_frame(); if (!gSkipInterpolationTitleScreen) { patch_interpolations(delta); } send_display_list(gGfxSPTask); gfx_end_frame(); - - // delay - if (!configUncappedFramerate) { - f64 targetDelta = 1.0 / (f64) configFrameLimit; - f64 now = clock_elapsed_f64(); - f64 actualDelta = now - curTime; - if (actualDelta < targetDelta) { - f64 delay = ((targetDelta - actualDelta) * 1000.0); - if (delay > 0.0f) { WAPI.delay((u32) delay); } - } - } - + frames++; + + if (configUncappedFramerate) { continue; } + + // Delay if our framerate is capped. + f64 targetDelta = 1.0 / (f64) configFrameLimit; + f64 now = clock_elapsed_f64(); + f64 actualDelta = now - curTime; + if (actualDelta >= targetDelta) { continue; } + f64 delay = ((targetDelta - actualDelta) * 1000.0) - 1.0; + if (delay > 0.0f) { + WAPI.delay((u32)delay); + } } static u64 sFramesSinceFpsUpdate = 0; @@ -465,7 +470,7 @@ int main(int argc, char *argv[]) { // main loop while (true) { debug_context_reset(); - CTX_BEGIN(CTX_FRAME); + CTX_BEGIN(CTX_TOTAL); WAPI.main_loop(produce_one_frame); #ifdef DISCORD_SDK discord_update(); @@ -475,7 +480,12 @@ int main(int argc, char *argv[]) { fflush(stdout); fflush(stderr); #endif - CTX_END(CTX_FRAME); + CTX_END(CTX_TOTAL); + +#ifdef DEVELOPMENT + djui_ctx_display_update(); +#endif + djui_lua_profiler_update(); } return 0;