12 issues nuevos para implementacion paralela: text_editor, file_watcher, gl_texture_load, gl_compute+pingpong+DAG Compute, ImPlot3D, mesh_viewer, audio reactivo, animation curves, sql_workbench, http+ws inspector, scientific viz (5 charts), map_tiles, image_canvas + webcam_texture. Cada issue añade funciones al registry y un demo propio en primitives_gallery/demos_<feature>.cpp para minimizar conflictos en paralelo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.6 KiB
0027 — C++ gl_compute_shader + gl_pingpong_fbo + DAG node Compute
APP Metadata
| Campo | Valor |
|---|---|
| ID | 0027 |
| Estado | pendiente |
| Prioridad | alta |
| Tipo | feature — C++ gfx (cpp/functions/gfx) |
Dependencias
Recomendado leer primero gl_loader_cpp_gfx, gl_shader_cpp_gfx, gl_framebuffer_cpp_gfx, dag_catalog_cpp_gfx, dag_compile_cpp_gfx. Sin bloqueos.
Desbloquea: simulaciones GPGPU (particulas, fluidos), feedback loops (reaction-diffusion, blur multipass, bloom), cualquier shader que necesite estado entre frames. Triplica el alcance del DAG visual de shaders_lab.
Objetivo
Tres adiciones complementarias:
gl_compute_shader_cpp_gfx— carga + dispatch de compute shaders (GLSL#version 430 core+layout(local_size_*) in). API parejo agl_shader.gl_pingpong_fbo_cpp_gfx— wrapper de dosgl_framebuffercon swap A↔B en cada paso. Permite usar el output del frame N-1 como input del frame N (feedback).- DAG kind
Compute— nuevoDagNodeKind::Computeendag_catalog/dag_compile. Nodo que ejecuta un compute shader sobre la imagen actual, con N iteraciones configurable.
Demo en primitives_gallery: reaction-diffusion (Gray-Scott) usando ping-pong FBO + compute shader.
Contexto
gl_shader solo soporta fragment shaders. El DAG actual es estrictamente fragment-pipeline (gen → op → blend). No hay forma de:
- Persistir estado entre frames (necesario para feedback effects).
- Hacer GPGPU verdadero (compute con buffers / images).
- Implementar efectos como fluid sim, particulas o blur multipass eficientes.
OpenGL compute shaders requieren #version 430 core (= GL 4.3). El proyecto ya pide GL 3.3+; subir el minimo solo para los nodos compute es aceptable (graceful degrade si la GPU no lo soporta).
Arquitectura
cpp/functions/gfx/
├── gl_compute_shader.h # NEW
├── gl_compute_shader.cpp # NEW
├── gl_compute_shader.md # NEW
├── gl_pingpong_fbo.h # NEW
├── gl_pingpong_fbo.cpp # NEW
├── gl_pingpong_fbo.md # NEW
├── dag_types.h # MOD: añadir DagNodeKind::Compute
├── dag_catalog.cpp/.h # MOD: registrar nodos compute (ej: ReactionDiffusion)
├── dag_compile.cpp/.h # MOD: emitir paso compute en pipeline
└── dag_uniforms.cpp/.h # MOD si los compute tienen params
cpp/apps/primitives_gallery/
├── demos_compute.cpp # NEW
├── demos.h # MOD
├── main.cpp # MOD
└── CMakeLists.txt # MOD
Pure core / impure shell
gl_compute_shaderygl_pingpong_fbo: ambospurity: impure,kind: function.dag_catalog/dag_compile: ya sonpure, mantener.dag_node_editor/dag_panel: ya sonimpure, no se tocan en este issue (los nodos compute aparecen automaticamente al añadirse al catalog).
API propuesta
namespace fn {
// gl_compute_shader.h
struct GlComputeProgram {
GLuint program = 0;
int local_x = 1, local_y = 1, local_z = 1;
bool ok() const { return program != 0; }
};
GlComputeProgram gl_compute_compile(const char* glsl_body); // body sin version
void gl_compute_destroy(GlComputeProgram&);
// Dispatch: bind images, set uniforms (callback opcional), glDispatchCompute, barrier.
void gl_compute_dispatch(const GlComputeProgram&, int groups_x, int groups_y, int groups_z = 1);
void gl_compute_bind_image(int unit, GLuint texture, GLenum access /*GL_READ_ONLY|WRITE|READ_WRITE*/, GLenum format = GL_RGBA8);
const char* gl_compute_last_error();
// gl_pingpong_fbo.h — dos FBO RGBA8 del mismo tamaño con A/B swap.
struct PingpongFbo {
Framebuffer a, b;
bool a_is_front = true; // front = ultimo escrito
};
PingpongFbo pingpong_create(int w, int h);
void pingpong_destroy(PingpongFbo&);
void pingpong_resize(PingpongFbo&, int w, int h);
void pingpong_swap(PingpongFbo&);
const Framebuffer& pingpong_front(const PingpongFbo&); // ultima lectura
const Framebuffer& pingpong_back (const PingpongFbo&); // siguiente write target
}
DAG: nuevo kind Compute
dag_catalog registra al menos un nodo de ejemplo: compute_blur_separable o compute_reaction_diffusion. Tras este issue queda abierto añadir mas (cada uno = un nuevo DagNode).
dag_compile: cuando emite un paso Compute, decide bindings (image read = ping-front, image write = pong-back) y devuelve metadatos para que el host haga dispatch + swap correctamente.
Tareas
Fase 1 — gl_compute_shader
- 1.1 Implementar wrapper minimo. Detectar version GL >= 4.3 al inicializar; si no, retornar
program == 0y guardar error "compute shaders require OpenGL 4.3+". - 1.2 Helper
gl_compute_bind_imageconglBindImageTexture. - 1.3
.mdcon frontmatter (purity: impure,kind: function,error_type).
Fase 2 — gl_pingpong_fbo
- 2.1 Implementar wrapper que reusa el
gl_framebufferexistente. Resize propaga a los dos. - 2.2
.mdcon frontmatter.
Fase 3 — DAG Compute kind
- 3.1 Añadir
DagNodeKind::Computeendag_types.h+ serializacion (json IO). - 3.2
dag_catalog: registrar nodo de ejemplocompute_blur_2pass(separable Gaussian blur, 2 dispatches via flag uniformdirection). - 3.3
dag_compile: emitir step compute con suficiente metadata para que el host (un nuevo helper) haga el dispatch. - 3.4 Helper
dag_compute_run_step()— recibeDagStepcompute +PingpongFbo+ uniforms y hacedispatch + swap.
Fase 4 — Gallery demo
- 4.1
demos_compute.cppcondemo_compute_reaction_diffusion():PingpongFbo512×512 + compute shader Gray-Scott con sliders (feed, kill, dt). UsaImGui::Imagepara mostrar el front buffer cada frame. Boton "reset" rellena con seed. - 4.2 Registrar en gallery.
Fase 5 — Tests + docs
- 5.1 Test (Linux + GPU disponible, opcional via env var
FN_GPU_TESTS=1): compila un compute simple que escribevec4(1,0,0,1)y verifica viaglReadPixels. - 5.2 Test puro de
dag_compilecon un pipeline que mezcla nodosGen+Compute. - 5.3
./fn index+./fn show *_cpp_gfxpara los nuevos.
Ejemplo de uso
auto cs = fn::gl_compute_compile(R"glsl(
layout(local_size_x=8, local_size_y=8) in;
layout(rgba8, binding=0) uniform image2D src;
layout(rgba8, binding=1) uniform image2D dst;
void main() {
ivec2 p = ivec2(gl_GlobalInvocationID.xy);
vec4 c = imageLoad(src, p);
imageStore(dst, p, vec4(1.0 - c.rgb, 1.0));
}
)glsl");
auto pp = fn::pingpong_create(512, 512);
glUseProgram(cs.program);
fn::gl_compute_bind_image(0, fn::pingpong_front(pp).color_tex, GL_READ_ONLY);
fn::gl_compute_bind_image(1, fn::pingpong_back (pp).color_tex, GL_WRITE_ONLY);
fn::gl_compute_dispatch(cs, 64, 64);
fn::pingpong_swap(pp);
Decisiones de diseño
- Subir minimo a GL 4.3 solo para nodos Compute — el resto del pipeline sigue compilando con 3.3.
gl_compute_compilefalla con error claro en GPUs viejas. - Ping-pong fuera de FBO — wrapper aparte, no fusionado con
gl_framebuffer(mantenemos primitivos atomicos). - Catalog del DAG abierto — un solo nodo compute en este issue. Otros (fluid, particles) se añaden en issues posteriores reusando los wrappers.
Riesgos
- macOS no soporta compute shaders en GL 4.1 — documentar limitacion. En macOS el path Compute queda inactivo.
- Memory barriers: olvidar
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)produce datos basura. Encapsular engl_compute_dispatch. - Dispatch grande bloquea UI: documentar que dispatches > 1M pixels deben dividirse o bajar local_size.