El buffer de aristas pasa a estatico (16B/arista: source, target, color, flags) y solo se reupload cuando cambia el grafo. Las posiciones de los nodos viven en un Texture Buffer Object (RG32F) actualizado por frame; el vertex shader hace texelFetch con gl_VertexID & 1 para elegir endpoint. Draw call: glDrawArraysInstanced(GL_LINES, 0, 2, edge_count) con divisor=1. Para 100k aristas: el upload de 4.8 MB/frame baja a 0 en regimen estable. edge_alpha pasa a uniform; la pre-multiplicacion en CPU desaparece. GLSL sigue en 330 core (samplerBuffer/texelFetch estan en 1.40+). gl_loader gana glBufferSubData, glVertexAttribIPointer y glTexBuffer (en Linux ya estaban via GL_GLEXT_PROTOTYPES; ahora estan disponibles tambien en MinGW/Windows). Tests: nuevo test_graph_edge_static valida el layout de 16B y el packing RGBA8 del fallback. test_visual sigue verde — render visualmente identico. Bump graph_renderer 1.2.0 -> 1.3.0.
6.1 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, framework, params, output
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | tested | tests | test_file_path | file_path | framework | params | output | |||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| graph_renderer | function | cpp | viz | 1.3.0 | impure | GraphRenderer* graph_renderer_create(int width, int height, const GraphRendererConfig& config) | Renderer GPU de grafos con instanced rendering a FBO, compatible con ImGui::Image para visualizacion de grafos grandes |
|
|
|
false | error_go_core |
|
false | cpp/functions/viz/graph_renderer.cpp | imgui |
|
Handle opaco al renderer. Usar graph_renderer_draw() para obtener texture ID de OpenGL, pasable directamente a ImGui::Image() |
graph_renderer
Renderer GPU de grafos basado en OpenGL 3.3 core profile con instanced rendering. Renderiza nodos y aristas de un GraphData a un FBO interno y retorna el texture ID para integracion directa con ImGui::Image().
Funciones del API
// Ciclo de vida
GraphRenderer* graph_renderer_create(int width, int height, const GraphRendererConfig& config = {});
void graph_renderer_destroy(GraphRenderer* r);
void graph_renderer_resize(GraphRenderer* r, int width, int height);
// Renderizado
unsigned int graph_renderer_draw(GraphRenderer* r, const GraphData& graph,
float cam_x, float cam_y, float cam_zoom);
Ejemplo de uso con ImGui
// Inicializacion (una vez)
GraphRenderer* renderer = graph_renderer_create(800, 600);
// En el render loop
ImVec2 panel_size = ImGui::GetContentRegionAvail();
graph_renderer_resize(renderer, (int)panel_size.x, (int)panel_size.y);
unsigned int tex = graph_renderer_draw(renderer, graph_data,
cam_x, cam_y, cam_zoom);
ImGui::Image((ImTextureID)(uintptr_t)tex,
panel_size,
ImVec2(0, 1), ImVec2(1, 0)); // flip Y para OpenGL
// Destruccion
graph_renderer_destroy(renderer);
Notas de implementacion
Renderizado de nodos: Instanced rendering con un quad unitario [-0.5, 0.5] expandido por el tamano del nodo. El fragment shader aplica un SDF circular con anti-aliasing via smoothstep y un anillo de outline.
Renderizado de aristas: GL_LINES con datos de posicion y color empaquetados por arista. El ancho se controla con GraphRendererConfig::edge_width.
Transformacion de camara:
tx = -cam_x * zoom + width/2
ty = -cam_y * zoom + height/2
ndc = (screen / viewport) * 2 - 1
Paleta de comunidades: 10 colores ABGR usados cuando node.color == 0, seleccionados por node.community % 10.
Estado GL: Guarda y restaura GL_FRAMEBUFFER_BINDING y GL_VIEWPORT para ser compatible con el render loop de ImGui sin efectos secundarios.
Includes GL: Usa gfx/gl_loader.h (v1.1+). En Linux es no-op (incluye headers con GL_GLEXT_PROTOTYPES). En Windows expone los simbolos modernos via wglGetProcAddress con macros #define gl* fn_gl*. Cualquier app que use graph_renderer debe linkear gl_loader.cpp y llamar fn::gfx::gl_loader_init() una vez tras crear el contexto GL.
Notas
-
v1.3 (2026-04-29, issue 0049d): aristas via vertex pulling. API publica intacta.
- El buffer de aristas pasa a ser estatico (
source_idx, target_idx, color, flags× E, 16 bytes/arista) y solo se reupload cuando el grafo cambia (detectado por(edges_ptr, edge_count)— heuristica suficiente mientrasGraphDatano tengarevision). Para 100k aristas: 1.6 MB iniciales vs 4.8 MB/frame del esquema anterior — el upload baja a cero en regimen estable. - Las posiciones de los nodos se suben cada frame a un Texture Buffer Object
RG32F(vec2[], 8 bytes/nodo). El vertex shader de aristas hacetexelFetch(u_node_pos, idx)conidxderivado degl_VertexID & 1(0=source, 1=target). - Draw call:
glDrawArraysInstanced(GL_LINES, 0, 2, edge_count)— 1 instancia por arista, 2 vertices por linea, todos los atributos condivisor=1. - Frustum cull de aristas eliminado en CPU (la GPU clipea fuera de viewport por su cuenta). Se mantiene para nodos.
edge_alphapasa a uniform en el shader; la pre-multiplicacion en CPU desaparece y permite que el buffer estatico no dependa del config.- GLSL: 330 core (con
samplerBuffer/texelFetchque estan en 1.40+).gl_loaderganaglBufferSubData,glVertexAttribIPointeryglTexBuffer(Linux ya los tenia viaGL_GLEXT_PROTOTYPES).
- El buffer de aristas pasa a ser estatico (
-
v1.2 (2026-04-29, issue 0049c): tres optimizaciones internas, API publica intacta.
- RGBA8 packing: el buffer de instancia/vertice usa
uint32por color en lugar de 4 floats. Nodo: 28 → 16 bytes/instance (-43%). Edge: 24 → 12 bytes/vertex (-50%). Los shaders desempaquetan con bit shifts (compatible GL 3.30+, sin necesidad deunpackUnorm4x8que es 4.20+). Helpers expuestos en el .h:pack_rgba8,unpack_rgba8,modulate_alpha_rgba8(testeados entest_graph_pack_rgba8.cpp). - Capacity-tracked streaming buffers: el VBO se mantiene orphaned con
glBufferData(NULL, capacity)y se actualiza conglBufferSubDatasolo los bytes usados. La capacidad crece x2 cuando hace falta (inicial: 4096 nodos / 8192 vertices de aristas) → reallocaciones en O(log N). Staging CPU reutilizado entre frames. - Frustum cull: nodos y aristas fuera del viewport AABB (con margen 10%) se saltan en CPU antes del upload. Para nodos, solo los visibles entran en el instance buffer (
glDrawArraysInstancedconvisible_count). Para aristas, AABB del segmento contra viewport. Pop-in al borde mitigado por el margen.
Resultado esperado: ~20k nodos a 60fps en GPU integrada cuando
cam_zoommantiene la mayoria fuera del viewport. - RGBA8 packing: el buffer de instancia/vertice usa
-
v1.1 (2026-04-25): cambia de raw
<GL/glext.h>agfx/gl_loader.hpara que compile en cross-compile MinGW. Sin cambios funcionales — el binario Linux es bit-equivalente.