/* * Copyright (c) Camden Dixie O'Brien * SPDX-License-Identifier: AGPL-3.0-only */ #include "engine_hooks.h" #include #include #include #include #define VT100_CURSORTOPLEFT "\33[H" #define VT100_CLEAR "\33[2J" #ifdef PERFMON #define GETPERF(x) x = SDL_GetPerformanceCounter() #else #define GETPERF(x) #endif typedef struct { double freq; uint64_t start, evt, update, render; double max_start, max_evt, max_update, max_render, max_total; } perf_t; int main(int argc, char *argv[]) { int err = SDL_Init(SDL_INIT_VIDEO); assert(0 == err); SDL_Window *window = SDL_CreateWindow( game_conf.win.title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, game_conf.win.w, game_conf.win.h, 0); assert(NULL != window); SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); assert(NULL != renderer); SDL_DisplayMode mode; assert(SDL_GetWindowDisplayMode(window, &mode) == 0); const double interval = 1.0 / mode.refresh_rate; void *gamemem = calloc(1, game_conf.memsize); game_init(argc, argv, gamemem, renderer); #ifdef PERFMON perf_t perf = { .freq = SDL_GetPerformanceFrequency() / 1000000.0 }; uint64_t frame = 0; #endif while (1) { GETPERF(perf.start); // Handle all events currently in queue SDL_Event evt; while (SDL_PollEvent(&evt)) { if (game_evt(gamemem, &evt) != GAMESTATUS_OK) goto quit; } GETPERF(perf.evt); // Update game state if (game_update(gamemem, interval) != GAMESTATUS_OK) goto quit; GETPERF(perf.update); // Render frame SDL_RenderClear(renderer); game_render(gamemem, renderer, SDL_GetTicks64()); GETPERF(perf.render); #ifdef PERFMON // Print performance analysis every 16 frames if ((frame & 15) == 0) { const double evt = (perf.evt - perf.start) / perf.freq; if (evt > perf.max_evt) perf.max_evt = evt; const double update = (perf.update - perf.evt) / perf.freq; if (update > perf.max_update) perf.max_update = update; const double render = (perf.render - perf.update) / perf.freq; if (render > perf.max_render) perf.max_render = render; const double total = (perf.render - perf.start) / perf.freq; if (total > perf.max_total) perf.max_total = total; const double total_pc = 100 * total / (1000000 * interval); printf( VT100_CLEAR VT100_CURSORTOPLEFT "evt\t[max %10.3f μs] %10.3f μs\n" "update\t[max %10.3f μs] %10.3f μs\n" "render\t[max %10.3f μs] %10.3f μs\n" "total\t[max %10.3f μs] %10.3f μs -- %.2f%% of %.3f ms\n", perf.max_evt, evt, perf.max_update, update, perf.max_render, render, perf.max_total, total, total_pc, 1000 * interval); } ++frame; #endif // Present frame SDL_RenderPresent(renderer); } quit: game_teardown(gamemem); free(gamemem); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); }