--- name: gpu_ssbo kind: function lang: cpp domain: gfx version: "1.0.0" purity: impure signature: "Ssbo ssbo_create(size_t bytes, const void* initial_data, GLenum usage); void ssbo_bind(const Ssbo&, unsigned binding); void ssbo_upload(const Ssbo&, size_t offset, size_t bytes, const void* data); void ssbo_readback(const Ssbo&, size_t offset, size_t bytes, void* out); void ssbo_destroy(Ssbo&)" description: "Lifecycle de Shader Storage Buffer Objects (SSBO) para datos arbitrarios CPU<->GPU. create/bind/upload/readback/destroy. Pareja generica de mesh_gpu para computes y Monte Carlo intensivo." tags: [opengl, ssbo, gpu, compute, buffer, gfx] uses_functions: ["gl_loader_cpp_gfx"] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [GL/gl.h, GL/glext.h] tested: false tests: [] test_file_path: "" file_path: "cpp/functions/gfx/gpu_ssbo.cpp" framework: opengl params: - name: bytes desc: "Tamano del buffer en bytes. Si 0, ssbo_create devuelve un Ssbo vacio sin tocar GL." - name: initial_data desc: "Puntero a datos iniciales (nullptr = sin inicializar; el shader es responsable del primer write)." - name: usage desc: "GLenum hint: GL_DYNAMIC_DRAW (default, CPU escribe a menudo), GL_STATIC_DRAW, GL_DYNAMIC_COPY (compute<->compute)." - name: binding desc: "Indice del layout(std430, binding=N) que matchea el shader." - name: offset desc: "Offset en bytes dentro del buffer." - name: data desc: "Puntero a bytes a subir (upload) o destino donde escribir bytes leidos (readback)." output: "Ssbo con id GL valido (o 0 si bytes=0). El caller mantiene la struct y la pasa a las demas funciones; ssbo_destroy resetea id/bytes a 0." --- # gpu_ssbo Wrapper canonico de Shader Storage Buffer Objects para uso con compute shaders. Pensado como base de Monte Carlo / MCMC en GPU: el SSBO es el medio para llevar samples, walkers, contadores e histogramas entre passes y de vuelta a CPU para visualizacion con `histogram_cpp_viz`, `heatmap_cpp_viz`, etc. ## Ciclo de vida ```cpp fn::gfx::Ssbo samples = fn::gfx::ssbo_create(N * sizeof(float)); // Bind antes de cada dispatch que quiera leer/escribir el buffer: fn::gfx::ssbo_bind(samples, /*binding=*/0); glDispatchCompute( ... ); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); // Lectura sincrona a CPU: std::vector host(N); fn::gfx::ssbo_readback(samples, 0, N * sizeof(float), host.data()); fn::gfx::ssbo_destroy(samples); ``` ## Subir datos iniciales ```cpp std::vector seeds(N); fn::gfx::seed_walkers_init(0xDEADBEEF, seeds.data(), N); fn::gfx::Ssbo seed_buf = fn::gfx::ssbo_create( N * sizeof(unsigned int), seeds.data(), GL_STATIC_DRAW ); ``` O bien crear vacio y rellenar luego: ```cpp fn::gfx::Ssbo buf = fn::gfx::ssbo_create(N * sizeof(unsigned int)); fn::gfx::ssbo_upload(buf, 0, N * sizeof(unsigned int), seeds.data()); ``` ## Notas - `ssbo_readback` bloquea el pipeline. Para readbacks frecuentes considerar PBO o `glFenceSync` (no implementado aqui — añadirlo cuando haga falta). - El caller es responsable de los `glMemoryBarrier` entre dispatches que leen lo que un dispatch anterior escribio. - El buffer se enlaza a `GL_SHADER_STORAGE_BUFFER` para create/upload/readback y al binding indexado via `glBindBufferBase` solo en `ssbo_bind`. Esto evita estado pegajoso entre llamadas. - Tamano maximo en GL 4.3: `GL_MAX_SHADER_STORAGE_BLOCK_SIZE` (en RTX 3070 ~ 2 GB). Para Monte Carlo de 10^7 samples float fp32 son 40 MB — sobrado.