feat(gpu): migrar a SDL3_GPU amb 2-pass rendering i post-processat

- Infraestructura GPU: GpuContext, GpuPipeline, GpuSpriteBatch, GpuTexture
- Engine::render() migrat a 2-pass: sprites → offscreen R8G8B8A8 → swapchain + vignette
- UI/text via software renderer (SDL3_ttf) + upload com a textura overlay GPU
- CMakeLists.txt actualitzat per incloure subsistema gpu/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 22:08:12 +01:00
parent 736db8cf41
commit 00a5875c92
11 changed files with 1341 additions and 240 deletions

View File

@@ -1,8 +1,9 @@
#pragma once
#include <SDL3/SDL_events.h> // for SDL_Event
#include <SDL3/SDL_render.h> // for SDL_Renderer
#include <SDL3/SDL_render.h> // for SDL_Renderer (ui_renderer_ software renderer)
#include <SDL3/SDL_stdinc.h> // for Uint64
#include <SDL3/SDL_surface.h> // for SDL_Surface (ui_surface_)
#include <SDL3/SDL_video.h> // for SDL_Window
#include <array> // for array
@@ -15,6 +16,10 @@
#include "boids_mgr/boid_manager.hpp" // for BoidManager
#include "defines.hpp" // for GravityDirection, ColorTheme, ShapeType
#include "external/texture.hpp" // for Texture
#include "gpu/gpu_context.hpp" // for GpuContext
#include "gpu/gpu_pipeline.hpp" // for GpuPipeline
#include "gpu/gpu_sprite_batch.hpp" // for GpuSpriteBatch
#include "gpu/gpu_texture.hpp" // for GpuTexture
#include "input/input_handler.hpp" // for InputHandler
#include "scene/scene_manager.hpp" // for SceneManager
#include "shapes_mgr/shape_manager.hpp" // for ShapeManager
@@ -124,14 +129,32 @@ class Engine {
std::unique_ptr<UIManager> ui_manager_; // Gestión de UI (HUD, FPS, notificaciones)
std::unique_ptr<AppLogo> app_logo_; // Gestión de logo periódico en pantalla
// Recursos SDL
// === SDL window ===
SDL_Window* window_ = nullptr;
SDL_Renderer* renderer_ = nullptr;
// === SDL_GPU rendering pipeline ===
std::unique_ptr<GpuContext> gpu_ctx_; // Device + swapchain
std::unique_ptr<GpuPipeline> gpu_pipeline_; // Sprite + postfx pipelines
std::unique_ptr<GpuSpriteBatch> sprite_batch_; // Per-frame vertex/index batch
std::unique_ptr<GpuTexture> offscreen_tex_; // Offscreen render target (Pass 1)
std::unique_ptr<GpuTexture> white_tex_; // 1×1 white (background gradient)
std::unique_ptr<GpuTexture> ui_tex_; // UI text overlay texture
// GPU sprite textures (one per ball skin, parallel to textures_/texture_names_)
std::unique_ptr<GpuTexture> gpu_texture_; // Active GPU sprite texture
std::vector<std::unique_ptr<GpuTexture>> gpu_textures_; // All GPU sprite textures
// === SDL_Renderer (software, for UI text via SDL3_ttf) ===
// Renders to ui_surface_, then uploaded as gpu texture overlay.
SDL_Renderer* ui_renderer_ = nullptr;
SDL_Surface* ui_surface_ = nullptr;
// Legacy Texture objects — kept for ball physics sizing and AppLogo
std::shared_ptr<Texture> texture_ = nullptr; // Textura activa actual
std::vector<std::shared_ptr<Texture>> textures_; // Todas las texturas disponibles
std::vector<std::string> texture_names_; // Nombres de texturas (sin extensión)
size_t current_texture_index_ = 0; // Índice de textura activa
int current_ball_size_ = 10; // Tamaño actual de pelotas (dinámico, se actualiza desde texture)
int current_ball_size_ = 10; // Tamaño actual de pelotas (dinámico)
// Estado del simulador
bool should_exit_ = false;
@@ -143,12 +166,12 @@ class Engine {
// Sistema de zoom dinámico
int current_window_zoom_ = DEFAULT_WINDOW_ZOOM;
// V-Sync
// V-Sync y fullscreen
bool vsync_enabled_ = true;
bool fullscreen_enabled_ = false;
bool real_fullscreen_enabled_ = false;
bool kiosk_mode_ = false;
ScalingMode current_scaling_mode_ = ScalingMode::INTEGER; // Modo de escalado actual (F5)
ScalingMode current_scaling_mode_ = ScalingMode::INTEGER;
// Resolución base (configurada por CLI o default)
int base_screen_width_ = DEFAULT_SCREEN_WIDTH;
@@ -164,15 +187,13 @@ class Engine {
// Sistema de temas (delegado a ThemeManager)
std::unique_ptr<ThemeManager> theme_manager_;
int theme_page_ = 0; // Página actual de temas (0 o 1) para acceso por Numpad
int theme_page_ = 0;
// Modo de simulación actual (PHYSICS/SHAPE/BOIDS) — fuente de verdad para Engine
// El estado de figuras (active_shape_, scale, etc.) está en ShapeManager
// Modo de simulación actual (PHYSICS/SHAPE/BOIDS)
SimulationMode current_mode_ = SimulationMode::PHYSICS;
// Sistema de Modo DEMO (auto-play) y LOGO
// Toda la lógica DEMO/LOGO y su estado vive en StateManager
int max_auto_scenario_ = 5; // Índice máximo en modos auto (resultado del benchmark)
int max_auto_scenario_ = 5;
// Escenario custom (--custom-balls)
int custom_scenario_balls_ = 0;
@@ -180,19 +201,10 @@ class Engine {
bool custom_auto_available_ = false;
bool skip_benchmark_ = false;
// Batch rendering
std::vector<SDL_Vertex> batch_vertices_;
std::vector<int> batch_indices_;
// Bucket sort per z-ordering (SHAPE mode)
static constexpr int DEPTH_SORT_BUCKETS = 256;
std::array<std::vector<size_t>, DEPTH_SORT_BUCKETS> depth_buckets_;
// Configuración del sistema de texto (constantes configurables)
static constexpr const char* TEXT_FONT_PATH = "data/fonts/determination.ttf";
static constexpr int TEXT_BASE_SIZE = 24; // Tamaño base para 240p
static constexpr bool TEXT_ANTIALIASING = true; // true = suavizado, false = píxeles nítidos
// Métodos principales del loop
void calculateDeltaTime();
void update();
@@ -201,24 +213,30 @@ class Engine {
// Benchmark de rendimiento (determina max_auto_scenario_ al inicio)
void runPerformanceBenchmark();
// Métodos auxiliares privados (llamados por la interfaz pública)
// Métodos auxiliares privados
// Sistema de cambio de sprites dinámico - Métodos privados
void switchTextureInternal(bool show_notification); // Implementación interna del cambio de textura
// Sistema de cambio de sprites dinámico
void switchTextureInternal(bool show_notification);
// Sistema de zoom dinámico - Métodos privados
// Sistema de zoom dinámico
int calculateMaxWindowZoom() const;
void setWindowZoom(int new_zoom);
void zoomIn();
void zoomOut();
void updatePhysicalWindowSize(); // Actualizar tamaño físico real de ventana
void updatePhysicalWindowSize();
// Rendering
// Rendering (GPU path replaces addSpriteToBatch)
void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f);
// Sistema de Figuras 3D - Métodos privados (thin wrappers a ShapeManager)
void toggleShapeModeInternal(bool force_gravity_on_exit = true); // Delega a ShapeManager + sincroniza current_mode_
void activateShapeInternal(ShapeType type); // Delega a ShapeManager + sets current_mode_ = SHAPE
void updateShape(); // Delega a ShapeManager::update()
void generateShape(); // Delega a ShapeManager::generateShape()
// Sistema de Figuras 3D
void toggleShapeModeInternal(bool force_gravity_on_exit = true);
void activateShapeInternal(ShapeType type);
void updateShape();
void generateShape();
// GPU helpers
bool loadGpuSpriteTexture(size_t index); // Upload one sprite texture to GPU
void recreateOffscreenTexture(); // Recreate when resolution changes
void renderUIToSurface(); // Render text/UI to ui_surface_
void uploadUISurface(SDL_GPUCommandBuffer* cmd_buf); // Upload ui_surface_ → ui_tex_
};