# Buffer Readback

Functions for reading GPU buffer contents back to CPU.

## readUintBuffer

Read back a storage buffer as `Uint32Array`.

Use this for buffers declared with `uint` type in TSL storage definitions.

```ts
import { readUintBuffer } from "vitest-browser-three";
import { instancedArray, atomicAdd, uint } from "three/tsl";

// renderer comes from ctx.renderer in rawComputeTest callback;
// counter.value is the StorageInstancedBufferAttribute of the atomic buffer.
const counter = instancedArray(1, "uint").toAtomic();
const kernel = Fn(() => {
  atomicAdd(counter.element(uint(0)), uint(1));
})().compute(64, [8]);

await renderer.computeAsync(kernel);

const data = await readUintBuffer(renderer, counter.value);
console.log(data[0]); // 64
```

**Returns**: `Promise<Uint32Array>`

**Note**: Pass `buffer.value` explicitly (the underlying `StorageInstancedBufferAttribute`), not the TSL node. The `.value` property provides the actual attribute that the GPU backend can read from.

```ts
const buffer = instancedArray(1, "uint").toAtomic();
// buffer is a TSL node; buffer.value is the StorageInstancedBufferAttribute
const data = await readUintBuffer(renderer, buffer.value);
```

## readIntBuffer

Read back a storage buffer as `Int32Array`.

Use this for buffers declared with `int` type in TSL storage definitions. Preserves signed integer values exactly.

```ts
import { readIntBuffer } from "vitest-browser-three";
import { instancedArray, atomicAdd, int } from "three/tsl";

// renderer comes from ctx.renderer in rawComputeTest callback;
// counter.value is the StorageInstancedBufferAttribute of the atomic buffer.
const counter = instancedArray(1, "int").toAtomic();
const kernel = Fn(() => {
  atomicAdd(counter.element(int(0)), int(1));
})().compute(32, [8]);

await renderer.computeAsync(kernel);

const data = await readIntBuffer(renderer, counter.value);
console.log(data[0]); // 32
```

**Returns**: `Promise<Int32Array>`

**Note**: Pass `buffer.value` explicitly (the underlying `StorageInstancedBufferAttribute`), not the TSL node. The `.value` property provides the actual attribute that the GPU backend can read from.

```ts
const buffer = instancedArray(1, "int").toAtomic();
// buffer is a TSL node; buffer.value is the StorageInstancedBufferAttribute
const data = await readIntBuffer(renderer, buffer.value);
```

## Supported Buffer Types

| Buffer Type    | Read Function    | Returns       |
| -------------- | ---------------- | ------------- |
| `uint` storage | `readUintBuffer` | `Uint32Array` |
| `int` storage  | `readIntBuffer`  | `Int32Array`  |

**For float assertions, use `gpuTest` / `gpuFuzzTest`.** They read back
float buffers internally, apply tolerance handling, and produce
component-wise failure diagnostics — no manual readback needed.

**Float buffers cannot be read back through the public API**, because
any float scenario that `rawComputeTest` could express is also expressible
through `gpuTest`, which provides a better testing experience.

## Usage with rawComputeTest

```ts
import { it, expect } from "vitest";
import { rawComputeTest, readUintBuffer } from "vitest-browser-three";
import { Fn, instancedArray, atomicAdd, uint } from "three/tsl";

it("my test", async () => {
  await rawComputeTest("my test", { backend: "webgpu" }, async ({ renderer }) => {
    const buffer = instancedArray(1, "uint").toAtomic();

    // Build and dispatch kernel
    const kernel = Fn(() => {
      atomicAdd(buffer.element(uint(0)), uint(1));
    })().compute(64, [8]);
    await renderer.computeAsync(kernel);

    // Read back results
    const data = await readUintBuffer(renderer, buffer.value);
    expect(data[0]).toBe(64);
  });
});
```
