Files
fn_registry/cpp/tests/test_graph_should_pause.cpp
egutierrez 427262b892 perf(viz): graph_renderer Tier 1 (RGBA8 + orphan + frustum cull) + force_layout auto-pause helper
Issue 0049c. Tres optimizaciones internas en graph_renderer.cpp + un
helper puro en graph_force_layout para detectar convergencia. API publica
intacta — solo cambian el layout interno de los buffers, el shader y
los costes por frame.

1. RGBA8 color packing
   - El instance buffer de nodos pasa de (x,y,size,r,g,b,a) 28B a
     (x,y,size,color_u32) 16B (-43%). Aristas: 24B → 12B/vertex (-50%).
   - Shaders desempaquetan con bit shifts (compatible GL 3.30+, no
     necesita unpackUnorm4x8 que es 4.20+).
   - Helpers expuestos: pack_rgba8 / unpack_rgba8 / modulate_alpha_rgba8
     en graph_renderer.h. Los GraphNode.color y la paleta ya tenian el
     layout correcto (R en LSB), asi que CPU ahora pasa el uint32 directo
     sin convertir a 4 floats por nodo y por frame.

2. Capacity-tracked streaming buffers
   - Sustituye el doble glBufferData de antes por:
       glBufferData(NULL, capacity, STREAM_DRAW)   // orphan + reserva
       glBufferSubData(0, used_bytes, data)        // solo lo usado
   - capacity crece x2 cuando hace falta (inicial 4096 nodos /
     8192 vertices de aristas) → reallocaciones en O(log N).
   - Staging CPU (NodeInstance* / EdgeVertex*) reusado entre frames con
     realloc, no malloc/free per frame.

3. Frustum cull (CPU-side)
   - AABB del viewport en world coords con margen 10%.
   - Aristas: skip si AABB del segmento no intersecta el viewport.
   - Nodos: solo los visibles entran al instance buffer; visible_count
     es el N que pasa a glDrawArraysInstanced. Pop-in de borde mitigado
     por el margen.

4. graph_force_layout_should_pause(low_frames, min_consecutive)
   - Helper puro: el caller mantiene el contador, la funcion solo
     decide si parar. Reemplaza la rama inline en demos_graph.cpp.
   - Test Catch2 con secuencias artificiales.

Tests: test_graph_pack_rgba8 (16401 asserts, 4 cases — roundtrip exhaustivo
+ alpha modulation + clamp). test_graph_should_pause (3 cases, 14 asserts).
Los 29 tests del cpp/tests/ siguen verdes (incluido test_visual con goldens).

Bump versiones:
- graph_renderer 1.1.0 → 1.2.0
- graph_force_layout 1.0.0 → 1.1.0  (tested: true via should_pause test)
2026-04-29 22:17:13 +02:00

48 lines
1.8 KiB
C++

// Unit tests for graph_force_layout_should_pause — el helper puro que el
// caller usa para decidir si parar la simulacion tras N frames consecutivos
// con energia < umbral. La logica del contador es responsabilidad del caller;
// la funcion solo decide "ya cumple" en base al contador y al umbral.
#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"
#include "viz/graph_force_layout.h"
TEST_CASE("should_pause requires consecutive frames over threshold", "[viz][pause]") {
const int min_consec = 30;
REQUIRE_FALSE(graph_force_layout_should_pause(0, min_consec));
REQUIRE_FALSE(graph_force_layout_should_pause(1, min_consec));
REQUIRE_FALSE(graph_force_layout_should_pause(29, min_consec));
REQUIRE (graph_force_layout_should_pause(30, min_consec));
REQUIRE (graph_force_layout_should_pause(31, min_consec));
REQUIRE (graph_force_layout_should_pause(1000, min_consec));
}
TEST_CASE("should_pause with min_consecutive=0 always pauses", "[viz][pause]") {
// Edge case: si el caller pide 0 frames, considerar siempre convergido.
REQUIRE(graph_force_layout_should_pause(0, 0));
REQUIRE(graph_force_layout_should_pause(1, 0));
}
TEST_CASE("should_pause emulating a low->high->low sequence", "[viz][pause]") {
// Simula la logica del demo: el caller resetea low_frames cuando energy
// sube. should_pause solo depende del valor actual.
int low = 0;
const int target = 5;
// Acumulamos hasta 4: aun no.
for (int i = 0; i < 4; ++i) {
low++;
REQUIRE_FALSE(graph_force_layout_should_pause(low, target));
}
// El caller detecta energia alta -> reset.
low = 0;
REQUIRE_FALSE(graph_force_layout_should_pause(low, target));
// Acumulamos los 5 que pide el target.
for (int i = 0; i < 5; ++i) low++;
REQUIRE(graph_force_layout_should_pause(low, target));
}