Files
fn_registry/dev/issues/0049c-graph-renderer-tier1.md
T
egutierrez f8f72e4bf7 chore(issues): plan 0049 OSINT graph viewer multi-issue
Aggregates the planning artifacts for the 0049 series (umbrella + 0049a..0049k):

- New rule cpp_apps.md (registered in INDEX) — standardize structure, CMake
  patterns, app.md frontmatter and sub-repo for C++ apps; points to the
  authoritative cpp/PATTERNS.md and cpp/DESIGN_SYSTEM.md.
- Feature flag osint_graph_v1 (disabled until 0049k closes).
- Issue 0049 (umbrella) and sub-issues 0049b..0049k describing the GPU
  rendering system, force-layout, types, sources, labels and the final
  graph_explorer app integration.
- README updated with the new rows (all pending; 0049a will flip to
  completed in the next commit).
2026-04-29 21:08:36 +02:00

4.6 KiB
Raw Blame History

0049c — graph_renderer Tier 1: RGBA8, orphan buffers, frustum cull, auto-pause

Metadata

Campo Valor
ID 0049c
Estado pendiente
Prioridad alta
Tipo mejora rendimiento — parte de #0049

Dependencias

Bloqueada por: 0049b (recomendado pero no estricto — cambios funcionan en 3.3 tambien). Desbloquea: 0049d, demos perf-realistas para issues posteriores.


Objetivo

Optimizaciones baratas y de gran impacto sobre graph_renderer.cpp y graph_force_layout para subir de ~5k nodos a ~20k nodos a 60fps en GPU integrada sin cambiar la API publica.

Contexto

Hoy el renderer:

  • Empaqueta colores como 4 floats × N (16 bytes/nodo) en el instance buffer.
  • Llama glBufferData cada frame → driver realloca el VBO.
  • Sube todas las aristas siempre, aunque esten fuera del viewport.
  • Force layout corre cada frame aunque la energia sea minima (estado convergido).

Arquitectura

cpp/functions/viz/
├── graph_renderer.{h,cpp}                 # MOD
├── graph_renderer.md                       # MOD: bump version (1.x)
├── graph_force_layout.{h,cpp}             # MOD: helper auto_pause
└── graph_force_layout.md                   # MOD

Sin cambios en la API publica — son optimizaciones internas.

Tareas

Fase 1 — Color packing RGBA8

  • 1.1 En el instance buffer, cambiar layout de (x, y, size, r, g, b, a) floats a (x, y, size, color_rgba8) donde color_rgba8 es uint32 packed.
  • 1.2 Ajustar shader vertex de nodos: layout(location=3) in uint a_color; vec4 col = unpackUnorm4x8(a_color);.
  • 1.3 Ajustar el packing en CPU: helper pack_rgba8(r,g,b,a) = (a<<24)|(b<<16)|(g<<8)|r.
  • 1.4 Idem para el buffer de aristas (color por vertex → uint32 por vertex).

Fase 2 — Orphan buffer pattern

  • 2.1 Reemplazar glBufferData(GL_ARRAY_BUFFER, sz, data, GL_DYNAMIC_DRAW) por:
    glBufferData(GL_ARRAY_BUFFER, capacity_bytes, nullptr, GL_STREAM_DRAW);  // orphan
    glBufferSubData(GL_ARRAY_BUFFER, 0, used_bytes, data);
    
  • 2.2 Mantener capacity_bytes interno en el GraphRenderer y crecer al doble si used_bytes > capacity.

Fase 3 — Frustum cull aristas

  • 3.1 Calcular AABB visible en world coords:
    float wx0 = cam_x - (width/2)/zoom;  float wx1 = cam_x + (width/2)/zoom;
    float wy0 = cam_y - (height/2)/zoom; float wy1 = cam_y + (height/2)/zoom;
    
  • 3.2 En el bucle de aristas, skip si AABB de la arista (segmento source→target con margen) no intersecta el viewport AABB.
  • 3.3 Nodos: similar — skip nodos cuyo AABB (centro ± size) cae fuera. Como son draws instanced, el cull se hace empaquetando solo los visibles en el instance buffer (mantener un counter visible_count).

Fase 4 — Auto-pause force layout

  • 4.1 En graph_force_layout.h, anadir helper:
    // Devuelve true si la energia ha caido bajo el umbral durante N frames consecutivos.
    bool graph_force_layout_should_pause(float energy, float threshold, int min_consecutive);
    
  • 4.2 Documentar uso en el .md. El consumer guarda un contador interno; el helper es puro.
  • 4.3 Migrar demos_graph.cpp para usarlo y para no invocar _step cuando paused == true. Boton "Resume" ya existe.

Fase 5 — Tests + benchmark

  • 5.1 Test Catch2 sobre pack_rgba8/unpack_rgba8: roundtrip exacto.
  • 5.2 Test Catch2 sobre graph_force_layout_should_pause: secuencias artificiales.
  • 5.3 Benchmark manual en demos_graph con N=20000: anotar fps antes/despues en el .md de la funcion (notes:).

Fase 6 — Cleanup

  • Bump version del .md de graph_renderer a 1.1.0 y de graph_force_layout a 1.1.0.
  • fn index y verificar.
  • Commit perf(viz): graph_renderer Tier 1 (RGBA8, orphan, cull) + force_layout auto-pause.

Criterio de done

  • demos_graph con 20k nodos a 60fps en GPU integrada de pruebas.
  • Tests verdes.
  • nvidia-smi o radeontop muestran que la CPU baja respecto al baseline (perfilar con Tracy si TRACY_ENABLE).

Riesgos

Riesgo Mitigacion
unpackUnorm4x8 no esta en GL 3.3 sin extension Esta en core 4.0+; con bump 0049b ya disponible. Si 0049b no se mergea antes, fallback a (color>>0)&0xff)/255.0 manual
Frustum cull provoca pop-in en bordes Anadir margen del 10% del viewport AABB
Crecimiento de capacity buffer en streaming Crecer al doble; documentar capacity inicial razonable (4096 nodos)