From 9971052f14b6942bcf6297fd12e2e62c0fb077c5 Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Sat, 7 Jun 2025 16:16:52 +0200 Subject: [PATCH] Frame budgets now in nanoseconds, game runs okayish on 5 % CPU --- game/src/chunk/chunkman.c | 34 +++++++++++++++++++--------------- game/src/chunk/chunkman.h | 3 +-- game/src/entity/entity.h | 11 ++++++++--- game/src/entity/entman.c | 18 ++++++++++-------- game/src/entity/entman.h | 3 +-- game/src/main.c | 2 +- 6 files changed, 40 insertions(+), 31 deletions(-) diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index 0ba04df..cac2de3 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -11,7 +11,6 @@ static GHashTable *chunks; static GHashTable *chunk_meshes; static bool bound = false; -static int frame_chunks = 0; guint chunkman_ivec2_hash (gconstpointer key) @@ -113,22 +112,25 @@ chunkman_tick (vec3 position) int cx, cz; chunkman_world_to_chunk (position[0], position[2], &cx, &cz); - unsigned int frame_time = SDL_GetTicks (); - frame_chunks = 0; + uint64_t start = SDL_GetPerformanceCounter (); + uint64_t freq = SDL_GetPerformanceFrequency (); + double elapsed_us = 0; for (int z = cz - RENDER_DISTANCE - 1; z <= cz + RENDER_DISTANCE + 1; ++z) { for (int x = cx - RENDER_DISTANCE - 1; x <= cx + RENDER_DISTANCE + 1; ++x) { + uint64_t now = SDL_GetPerformanceCounter (); + elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; + + if (elapsed_us > CHUNK_FRAME_BUDGET_US) + { + return; + } + if (chunkman_get_Chunk_at (x, z) == NULL) { chunkman_generate_Chunk_at (x, z); - ++frame_chunks; - } - - if (frame_chunks > CHUNKS_PER_FRAME || SDL_GetTicks () - frame_time > CHUNK_FRAME_BUDGET) - { - return; } } } @@ -137,15 +139,17 @@ chunkman_tick (vec3 position) { for (int x = cx - RENDER_DISTANCE; x <= cx + RENDER_DISTANCE; ++x) { + uint64_t now = SDL_GetPerformanceCounter (); + elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; + + if (elapsed_us > CHUNK_FRAME_BUDGET_US) + { + return; + } + if (chunkman_get_ChunkMesh_at (x, z) == NULL) { chunkman_generate_ChunkMesh_at (x, z); - ++frame_chunks; - } - - if (frame_chunks > CHUNKS_PER_FRAME || SDL_GetTicks () - frame_time > CHUNK_FRAME_BUDGET) - { - return; } } } diff --git a/game/src/chunk/chunkman.h b/game/src/chunk/chunkman.h index 83a17f4..25bd465 100644 --- a/game/src/chunk/chunkman.h +++ b/game/src/chunk/chunkman.h @@ -12,8 +12,7 @@ #define RENDER_DISTANCE 5 #define RENDER_SQR (RENDER_DISTANCE*RENDER_DISTANCE) #define TERRAIN_HEIGHT 8.0 -#define CHUNK_FRAME_BUDGET 5 -#define CHUNKS_PER_FRAME 1 +#define CHUNK_FRAME_BUDGET_US 100 void chunkman_init (); void chunkman_tick (vec3 position); diff --git a/game/src/entity/entity.h b/game/src/entity/entity.h index d4e288a..8fa41c4 100644 --- a/game/src/entity/entity.h +++ b/game/src/entity/entity.h @@ -1,9 +1,11 @@ #pragma once -#include +/* TODO: In the future, if entities are out of the tick radius, when + they reappear, calculate what would happen to them during the time + they were out of the radius. Useful for growing plants and + whatnot. */ -/* There should also be an entity mesh type of QUAD1, as billboards - always face the camera, thus the back side need not be rendered. */ +#include typedef struct Entity { @@ -20,6 +22,9 @@ typedef struct Entity void *userdata; void (*on_tick) (struct Entity *self); + bool tick_me_i_dont_care; /* Tick this entity regardless of the + distance and other + predicates. Useful for NPCs. */ vec3 position; vec3 rotation; diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index 61b7b88..3e60a91 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -16,8 +16,6 @@ int n_frame_ents; static GArray *entities; static GQueue *spawn_requests; -static int frame_ents = 0; - static SimpleMesh mesh_quad1, mesh_quad2, mesh_quad_x, mesh_cube; static unsigned int last_program = -1; static unsigned int last_type = -1; @@ -90,15 +88,19 @@ spawn_queue_process_one () void entman_tick () { - /* Handle spawn requests. */ - unsigned int frame_time = SDL_GetTicks (); - frame_ents = 0; + uint64_t start = SDL_GetPerformanceCounter (); + uint64_t freq = SDL_GetPerformanceFrequency (); + double elapsed_us = 0; - while (!g_queue_is_empty (spawn_requests) && SDL_GetTicks () - frame_time < ENTITY_FRAME_BUDGET - && frame_ents < ENTITIES_PER_FRAME) + while (!g_queue_is_empty (spawn_requests)) { + uint64_t now = SDL_GetPerformanceCounter(); + elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; + + if (elapsed_us > ENTITY_FRAME_BUDGET_US) + break; + spawn_queue_process_one (); - ++frame_ents; } /* Handle on tick events. */ diff --git a/game/src/entity/entman.h b/game/src/entity/entman.h index 4e447c7..dc18810 100644 --- a/game/src/entity/entman.h +++ b/game/src/entity/entman.h @@ -17,8 +17,7 @@ #define ENTADD(entity) (entman_add_entity (entity)) -#define ENTITY_FRAME_BUDGET 2 -#define ENTITIES_PER_FRAME 16 +#define ENTITY_FRAME_BUDGET_US 100 typedef struct SpawnRequest { diff --git a/game/src/main.c b/game/src/main.c index 7a937e7..dc0951b 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -52,8 +52,8 @@ SDL_AppIterate (void *appstate) UNUSED (appstate); game_state_tick (SDL_GetTicks ()); - entman_tick (); chunkman_tick (camera_position); + entman_tick (); uiman_tick (); graphics_render ();