---
name: gpu_rng_glsl
kind: function
lang: cpp
domain: gfx
version: "1.0.0"
purity: pure
signature: "std::string glsl_rng_preamble(int seed_binding); void seed_walkers_init(uint64_t master_seed, uint32_t* out, int count)"
description: "Generador de preamble GLSL con primitivas PCG32 (uniform, normal, below) inyectables en compute shaders, mas helper CPU para sembrar N seeds deterministas via SplitMix64. Sin GL ni I/O — funciones puras que producen string y rellenan array."
tags: [glsl, rng, pcg32, splitmix64, montecarlo, compute, gpu, gfx]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [string, cstdint, cstdio]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/gfx/gpu_rng_glsl.cpp"
framework: opengl
params:
  - name: seed_binding
    desc: "Indice del binding std430 donde reside el SSBO uint rng_seeds[]. Tipicamente reservar el ultimo binding del shader (8 o 9)."
  - name: master_seed
    desc: "Semilla maestra de la que se derivan todas las semillas individuales. 0 se sustituye por la constante de Knuth para evitar arranques degenerados."
  - name: out
    desc: "Buffer destino de count uint32. Garantiza out[i] != 0 (requisito de PCG32)."
  - name: count
    desc: "Numero de semillas a generar. Igual al numero de threads/walkers que ejecutaran el compute."
output: "glsl_rng_preamble: string GLSL listo para concatenar como preamble de compile_compute. seed_walkers_init: rellena out[count] in-place. Ambas son puras."
---

# gpu_rng_glsl

Pareja CPU + GLSL para Monte Carlo en compute shaders.

## Calidad

PCG32 (variante recomendada por O'Neill, 2014) tiene state de 32 bits, periodo 2^32 por chain y supera los tests de PractRand hasta varios TB. Para Monte Carlo no criptografico es la opcion estandar moderna. Cada thread tiene su propio state independiente (sin contention atomico), asi que el periodo agregado de N chains es N · 2^32 — mas que suficiente para 10^10 samples.

`rng_normal` usa Box-Muller con cos (descarta la sin) — ~30 ciclos GPU por sample, un orden de magnitud mas barato que el Ziggurat y sin tablas de lookup que machacarian el cache.

## API GLSL inyectada por `glsl_rng_preamble`

```glsl
layout(std430, binding = <seed_binding>) buffer RngSeeds { uint rng_seeds[]; };

uint  pcg32       (inout uint state);
float rng_uniform (inout uint state);              // [0, 1)
float rng_normal  (inout uint state);              // N(0, 1)
uint  rng_below   (inout uint state, uint n);      // [0, n) sin sesgo
```

## Patron de uso

CPU:

```cpp
std::vector<unsigned int> seeds(N);
fn::gfx::seed_walkers_init(0xC0FFEE, seeds.data(), N);

fn::gfx::Ssbo seed_ssbo = fn::gfx::ssbo_create(
    N * sizeof(unsigned int), seeds.data(), GL_DYNAMIC_COPY);

auto rng_src = fn::gfx::glsl_rng_preamble(/*seed_binding=*/9);
auto r = fn::gfx::compile_compute(my_body, 64, rng_src);
```

GLSL (`my_body`):

```glsl
layout(std430, binding = 0) buffer Out { float samples[]; };
uniform uint u_count;

void main() {
    uint i = gl_GlobalInvocationID.x;
    if (i >= u_count) return;

    uint s = rng_seeds[i];
    samples[i] = rng_normal(s);
    rng_seeds[i] = s;   // persistir para el siguiente dispatch
}
```

Despacho:

```cpp
glUseProgram(r.program);
fn::gfx::ssbo_bind(out_ssbo,  0);
fn::gfx::ssbo_bind(seed_ssbo, 9);
glUniform1ui(loc_count, N);
fn::gfx::dispatch_1d(N, 64);
fn::gfx::barrier_storage();
```

## Notas

- El binding del SSBO de seeds es parametro porque cada shader puede usar bindings distintos para sus datos. Convencion sugerida: el ultimo binding del shader (8 o 9).
- Para reproducibilidad bit-exacta entre runs, mantener `master_seed` y N constantes; los samples seran identicos. Util para tests numericos.
- `seed_walkers_init` es deterministica y no depende de GL — se puede invocar en tests unitarios CPU sin contexto OpenGL.
- Para muestreo categorico (sampleTier de vr_tiered_lab) usar `rng_uniform` con cumulative-sum manual en el shader; un helper dedicado se puede añadir si aparece en multiples kernels.
