#pragma once #include "gfx/gpu_ssbo.h" #include namespace fn::gfx { // Estado opaco del binner. Cachea el programa compute, los uniforms y un // SSBO uint[nbins] de bins. Reutilizable across dispatches con el mismo // tamano; si nbins cambia se debe destruir y crear de nuevo. struct GpuHistogram1D { unsigned int program = 0; unsigned int loc_count = 0; unsigned int loc_nbins = 0; unsigned int loc_min = 0; unsigned int loc_inv_range = 0; Ssbo bins; // uint[nbins] — atomicAdd target int nbins = 0; }; // Crea binner para nbins bins. Compila el compute y reserva el SSBO uint[nbins]. GpuHistogram1D gpu_histogram_1d_create(int nbins); // Borra el SSBO de bins (todos a cero) sin tocar el programa. Llamar antes // de cada acumulacion para empezar de cero. void gpu_histogram_1d_clear(GpuHistogram1D& h); // Acumula un SSBO float[count] en los bins del binner. range_min y range_max // definen los limites; samples fuera del rango se descartan (no clamp). El // SSBO de samples debe estar bindeado por el caller en binding=0; el binner // bindea automaticamente sus bins en binding=1. // // Tras esta llamada se requiere barrier_storage() o barrier_buffer_update() // segun lo que el caller vaya a hacer despues. void gpu_histogram_1d_accumulate(GpuHistogram1D& h, const Ssbo& samples, int count, float range_min, float range_max); // Lee los counts de bins a CPU. out debe tener al menos h.nbins enteros. // Hace ssbo_readback (sincrono). void gpu_histogram_1d_readback(const GpuHistogram1D& h, unsigned int* out); // Libera programa + SSBO. Seguro multiples veces. void gpu_histogram_1d_destroy(GpuHistogram1D& h); } // namespace fn::gfx