#pragma once #include "gfx/gpu_ssbo.h" namespace fn::ds { // Estado opaco del simulador. Cachea el programa compute, los SSBOs de // salida (summary + tier_counts), el SSBO de tiers (parametros) y el // SSBO de seeds RNG. Reusable across runs con n_sessions y max_tiers // constantes; si cambian hay que destroy + create. struct McSessionSim { unsigned int program = 0; fn::gfx::Ssbo summary; // float[N*8]: final, pnl, max_dd, peak, // trough, spins, wins, longest_miss fn::gfx::Ssbo tier_counts; // uint[N*max_tiers]: hits por tier fn::gfx::Ssbo tiers; // vec2[max_tiers]: (q, m) por tier fn::gfx::Ssbo rng_seeds; // uint[N] PCG state por sesion int n_sessions = 0; int max_tiers = 8; // Uniform locations (cacheados) unsigned int loc_n_sessions = 0; unsigned int loc_n_spins = 0; unsigned int loc_n_tiers = 0; unsigned int loc_p_base = 0; unsigned int loc_cost = 0; unsigned int loc_start_bal = 0; unsigned int loc_mode = 0; unsigned int loc_mode_p1 = 0; unsigned int loc_mode_p2 = 0; }; enum class McSessionMode : int { Pure = 0, // p_eff = p_base (sin pity ni streak) Pity = 1, // ramp lineal p_base -> 1 entre soft y hard miss_streak Streak = 2 // p_eff = min(1, p_base * (1 + lambda * miss_streak)) }; struct McSessionParams { float p_base = 0.2f; float cost = 1.0f; float start_balance = 100.0f; int n_spins = 1000; int n_tiers = 0; // <= max_tiers del create const float* tiers_q = nullptr; // [n_tiers] pesos relativos (no normalizados) const float* tiers_m = nullptr; // [n_tiers] multiplicadores de payout McSessionMode mode = McSessionMode::Pure; float mode_p1 = 0.0f; // pity.soft / streak.lambda float mode_p2 = 0.0f; // pity.hard (no usado en streak) }; // Crea el simulador para N sesiones y hasta max_tiers tiers distintos. // Compila el compute y reserva los SSBOs. McSessionSim mc_session_sim_create(int n_sessions, int max_tiers = 8); // Re-siembra los seeds RNG a partir de master_seed (deterministico). Llamar // al menos una vez antes del primer run; subsiguientes runs persisten el // state (ofreciendo "continuacion" — util para acumular mas spins). void mc_session_sim_reseed(McSessionSim& s, unsigned long long master_seed); // Ejecuta una corrida completa: cada uno de los N sessions independientes // hace n_spins spins. Bloquea hasta que el dispatch termina y el barrier // esta satisfecho. NO hace readback — el caller decide cuando leer. void mc_session_sim_run(McSessionSim& s, const McSessionParams& p); // Lee summary a CPU. out debe tener n_sessions * 8 floats. // Layout por sesion: [final_balance, pnl, max_dd, peak, trough, spins, // wins, longest_miss]. void mc_session_sim_readback_summary(const McSessionSim& s, float* out); // Lee tier_counts a CPU. out debe tener n_sessions * max_tiers uints. // Layout: out[sid * max_tiers + tier_idx] = hits del tier_idx en la sesion. void mc_session_sim_readback_tier_counts(const McSessionSim& s, unsigned int* out); void mc_session_sim_destroy(McSessionSim& s); } // namespace fn::ds