From ea27a771abb849fa37233829802f5125060fd8c0 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 11 Mar 2026 20:30:32 +0100 Subject: [PATCH] benchmark inicial per a determinar modes de baix rendiment ajustats escenaris maxims i minims per als diferents modes automatics --- source/defines.hpp | 7 +++ source/engine.cpp | 94 ++++++++++++++++++++++++++++++++++------ source/engine.hpp | 5 +++ source/ui/ui_manager.cpp | 19 ++++++++ 4 files changed, 112 insertions(+), 13 deletions(-) diff --git a/source/defines.hpp b/source/defines.hpp index 48755f2..7e0bac1 100644 --- a/source/defines.hpp +++ b/source/defines.hpp @@ -53,6 +53,13 @@ constexpr float BALL_SPAWN_MARGIN = 0.15f; // Margen lateral para spawn (0.25 = // Escenarios de número de pelotas (teclas 1-8) constexpr int BALL_COUNT_SCENARIOS[8] = {10, 50, 100, 500, 1000, 5000, 10000, 50000}; +// Límites de escenario para modos automáticos (índices en BALL_COUNT_SCENARIOS) +// BALL_COUNT_SCENARIOS = {10, 50, 100, 500, 1000, 5000, 10000, 50000} +// 0 1 2 3 4 5 6 7 +constexpr int DEMO_AUTO_MIN_SCENARIO = 2; // mínimo 100 bolas +constexpr int DEMO_AUTO_MAX_SCENARIO = 7; // máximo sin restricción hardware (ajustado por benchmark) +constexpr int LOGO_MIN_SCENARIO_IDX = 4; // mínimo 1000 bolas (sustituye LOGO_MODE_MIN_BALLS) + // Estructura para representar colores RGB struct Color { int r, g, b; // Componentes rojo, verde, azul (0-255) diff --git a/source/engine.cpp b/source/engine.cpp index b001930..9cb2fe9 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -283,6 +283,9 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen, AppMod app_logo_.reset(); } + // Benchmark de rendimiento (determina max_auto_scenario_ para modos automáticos) + runPerformanceBenchmark(); + // Precalentar caché: shapes PNG (evitar I/O en primera activación de PNG_SHAPE) { unsigned char* tmp = nullptr; size_t tmp_size = 0; @@ -1289,7 +1292,7 @@ void Engine::executeDemoAction(bool is_lite) { if (is_lite) { // DEMO LITE: Verificar condiciones para salto a Logo Mode - if (static_cast(scene_manager_->getBallCount()) >= LOGO_MODE_MIN_BALLS && + if (static_cast(scene_manager_->getBallCount()) >= BALL_COUNT_SCENARIOS[LOGO_MIN_SCENARIO_IDX] && theme_manager_->getCurrentThemeIndex() == 5) { // MONOCHROME // 10% probabilidad de saltar a Logo Mode if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE) { @@ -1299,7 +1302,7 @@ void Engine::executeDemoAction(bool is_lite) { } } else { // DEMO COMPLETO: Verificar condiciones para salto a Logo Mode - if (static_cast(scene_manager_->getBallCount()) >= LOGO_MODE_MIN_BALLS) { + if (static_cast(scene_manager_->getBallCount()) >= BALL_COUNT_SCENARIOS[LOGO_MIN_SCENARIO_IDX]) { // 15% probabilidad de saltar a Logo Mode if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO) { state_manager_->enterLogoMode(true, current_screen_width_, current_screen_height_, scene_manager_->getBallCount()); @@ -1413,12 +1416,12 @@ void Engine::executeDemoAction(bool is_lite) { return; } - // Cambiar escenario (10%) - EXCLUIR índices 0, 6, 7 (1, 50K, 100K pelotas) + // Cambiar escenario (10%) - rango dinámico según benchmark de rendimiento accumulated_weight += DEMO_WEIGHT_SCENARIO; if (random_value < accumulated_weight) { - // Escenarios válidos: índices 1, 2, 3, 4, 5 (10, 100, 500, 1000, 10000 pelotas) - int valid_scenarios[] = {1, 2, 3, 4, 5}; - int new_scenario = valid_scenarios[rand() % 5]; + int auto_max = std::min(max_auto_scenario_, DEMO_AUTO_MAX_SCENARIO); + int range = auto_max - DEMO_AUTO_MIN_SCENARIO + 1; + int new_scenario = DEMO_AUTO_MIN_SCENARIO + (rand() % range); scene_manager_->changeScenario(new_scenario, current_mode_); // Si estamos en modo SHAPE, regenerar la figura con nuevo número de pelotas @@ -1573,9 +1576,10 @@ void Engine::executeRandomizeOnDemoStart(bool is_lite) { // changeScenario() creará las pelotas y luego llamará a generateShape() } - // 2. Escenario (excluir índices 0, 6, 7) - AHORA con current_mode_ ya establecido correctamente - int valid_scenarios[] = {1, 2, 3, 4, 5}; - int new_scenario = valid_scenarios[rand() % 5]; + // 2. Escenario - rango dinámico según benchmark de rendimiento + int auto_max = std::min(max_auto_scenario_, DEMO_AUTO_MAX_SCENARIO); + int range = auto_max - DEMO_AUTO_MIN_SCENARIO + 1; + int new_scenario = DEMO_AUTO_MIN_SCENARIO + (rand() % range); scene_manager_->changeScenario(new_scenario, current_mode_); // Si estamos en modo SHAPE, generar la figura y activar atracción @@ -1621,16 +1625,80 @@ void Engine::executeToggleGravityOnOff() { } } +// ============================================================================ +// BENCHMARK DE RENDIMIENTO +// ============================================================================ + +void Engine::runPerformanceBenchmark() { + int num_displays = 0; + SDL_DisplayID* displays = SDL_GetDisplays(&num_displays); + float monitor_hz = 60.0f; + if (displays && num_displays > 0) { + const auto* dm = SDL_GetCurrentDisplayMode(displays[0]); + if (dm && dm->refresh_rate > 0) monitor_hz = dm->refresh_rate; + SDL_free(displays); + } + + // Ocultar ventana y desactivar V-sync para medición limpia + SDL_HideWindow(window_); + SDL_SetRenderVSync(renderer_, 0); + + const int BENCH_DURATION_MS = 600; + const int WARMUP_FRAMES = 5; + + auto restore = [&]() { + SDL_SetRenderVSync(renderer_, vsync_enabled_ ? 1 : 0); + SDL_ShowWindow(window_); + scene_manager_->changeScenario(0, current_mode_); + last_frame_time_ = 0; + }; + + // Probar de más pesado a más ligero + for (int idx = DEMO_AUTO_MAX_SCENARIO; idx >= DEMO_AUTO_MIN_SCENARIO; --idx) { + scene_manager_->changeScenario(idx, current_mode_); + + // Warmup: estabilizar física y pipeline GPU + last_frame_time_ = 0; + for (int w = 0; w < WARMUP_FRAMES; ++w) { + calculateDeltaTime(); + SDL_Event e; while (SDL_PollEvent(&e)) {} + update(); + render(); + } + + // Medición + int frame_count = 0; + Uint64 start = SDL_GetTicks(); + while (SDL_GetTicks() - start < static_cast(BENCH_DURATION_MS)) { + calculateDeltaTime(); + SDL_Event e; + while (SDL_PollEvent(&e)) { /* descartar */ } + update(); + render(); + ++frame_count; + } + + float measured_fps = static_cast(frame_count) / (BENCH_DURATION_MS / 1000.0f); + if (measured_fps >= monitor_hz) { + max_auto_scenario_ = idx; + restore(); + return; + } + } + // Fallback: escenario mínimo + max_auto_scenario_ = DEMO_AUTO_MIN_SCENARIO; + restore(); +} + // ============================================================================ // CALLBACKS PARA STATEMANAGER - LOGO MODE // ============================================================================ // Callback para StateManager - Configuración visual al entrar a LOGO MODE void Engine::executeEnterLogoMode(size_t ball_count) { - // Verificar mínimo de pelotas - if (static_cast(ball_count) < LOGO_MODE_MIN_BALLS) { - // Ajustar a 5000 pelotas automáticamente - scene_manager_->changeScenario(5, current_mode_); // Escenario 5000 pelotas (índice 5 en BALL_COUNT_SCENARIOS) + // Verificar mínimo de pelotas (LOGO_MIN_SCENARIO_IDX = índice 4 → 1000 bolas) + if (scene_manager_->getCurrentScenario() < LOGO_MIN_SCENARIO_IDX) { + scene_manager_->changeScenario(LOGO_MIN_SCENARIO_IDX, current_mode_); } // Guardar estado previo (para restaurar al salir) diff --git a/source/engine.hpp b/source/engine.hpp index 80c10fb..1240457 100644 --- a/source/engine.hpp +++ b/source/engine.hpp @@ -104,6 +104,7 @@ class Engine { int getCurrentScreenHeight() const { return current_screen_height_; } int getBaseScreenWidth() const { return base_screen_width_; } int getBaseScreenHeight() const { return base_screen_height_; } + int getMaxAutoScenario() const { return max_auto_scenario_; } private: // === Componentes del sistema (Composición) === @@ -172,6 +173,7 @@ class Engine { // StateManager coordina los triggers y timers, Engine ejecuta las acciones float demo_timer_ = 0.0f; // Contador de tiempo para próxima acción float demo_next_action_time_ = 0.0f; // Tiempo aleatorio hasta próxima acción (segundos) + int max_auto_scenario_ = 5; // Índice máximo en modos auto (default conservador: 5000 bolas) // Sistema de convergencia para LOGO MODE (escala con resolución) // Usado por performLogoAction() para detectar cuando las bolas forman el logo @@ -211,6 +213,9 @@ class Engine { void update(); void render(); + // Benchmark de rendimiento (determina max_auto_scenario_ al inicio) + void runPerformanceBenchmark(); + // Métodos auxiliares privados (llamados por la interfaz pública) // Sistema de cambio de sprites dinámico - Métodos privados diff --git a/source/ui/ui_manager.cpp b/source/ui/ui_manager.cpp index 7073ea7..c9a1b28 100644 --- a/source/ui/ui_manager.cpp +++ b/source/ui/ui_manager.cpp @@ -276,6 +276,25 @@ void UIManager::renderDebugHUD(const Engine* engine, text_renderer_debug_->printAbsolute(margin, left_y, balls_text.c_str(), {128, 255, 128, 255}); // Verde claro left_y += line_height; + // Máximo de pelotas en modos automáticos (resultado del benchmark) + int max_auto_idx = engine->getMaxAutoScenario(); + int max_auto_balls = BALL_COUNT_SCENARIOS[max_auto_idx]; + std::string max_auto_text; + if (max_auto_balls >= 1000) { + std::string count_str = std::to_string(max_auto_balls); + std::string formatted; + int digits = count_str.length(); + for (int i = 0; i < digits; i++) { + if (i > 0 && (digits - i) % 3 == 0) formatted += ','; + formatted += count_str[i]; + } + max_auto_text = "Auto max: " + formatted; + } else { + max_auto_text = "Auto max: " + std::to_string(max_auto_balls); + } + text_renderer_debug_->printAbsolute(margin, left_y, max_auto_text.c_str(), {128, 255, 128, 255}); // Verde claro + left_y += line_height; + // V-Sync text_renderer_debug_->printAbsolute(margin, left_y, vsync_text_.c_str(), {0, 255, 255, 255}); // Cian left_y += line_height;