Game of Life: Tribes

#VRAM And Packing

#Packed Formats

Cell states are stored as integer tribe indexes packed into u32 words. Supported formats are 11, 22, 44, 88, 1616, and 3232 bits per cell.

Bits/cell Cells/word Word shift Cell shift Cell mask
11 3232 55 00 0x1
22 1616 44 11 0x3
44 88 33 22 0xF
88 44 22 33 0xFF
1616 22 11 44 0xFFFF
3232 11 00 55 0xFFFFFFFF

The smallest tight format for a tribe count is selected by state count thresholds: 22, 44, 1616, 256256, 6553665\,536, then 3232-bit fallback.
However, currently, only up to 256256 states are supported, so 1616-bit and 3232-bit packings are user-choice only.

#Frame Byte Size

A packed frame is a rectangular array of u32 words:

packedCols=colscellsPerWord\texttt{packedCols}=\left\lceil\frac{\texttt{cols}}{\texttt{cellsPerWord}}\right\rceil frameBytes=packedColsrows4\texttt{frameBytes}=\texttt{packedCols}\cdot\texttt{rows}\cdot4

The same formula is used by grid-size validation, packing validation, snapshots, recording, and exports.

#VRAM Budget

The worker computes device simulation capacity as:

maxSimulationBytes=min(maxBufferSize,maxStorageBufferBindingSize)maxRecordingBytes=min(maxSimulationBytes,1 GiB)vramBudgetBytes=max(2maxSimulationBytes,6maxRecordingBytes)\begin{aligned} \texttt{maxSimulationBytes} &= \min\left(\texttt{maxBufferSize},\,\texttt{maxStorageBufferBindingSize}\right) \\ \texttt{maxRecordingBytes} &= \min\left(\texttt{maxSimulationBytes},\,1\text{ GiB}\right) \\ \texttt{vramBudgetBytes} &= \max\left(2\cdot\texttt{maxSimulationBytes},\,6\cdot\texttt{maxRecordingBytes}\right) \end{aligned}

WebGPU does not expose the actual amount of GPU VRAM available to the browser. The displayed VRAM budget is therefore an estimate derived from WebGPU buffer limits and the engine's own buffer plan, not a direct hardware memory reading.

The 22 WebGPU limits in the first line come from the selected adapter/device:

  • maxBufferSize: the largest individual GPUBuffer the device allows the app to create.
  • maxStorageBufferBindingSize: the largest storage-buffer range the device allows a shader to bind and access in one binding.

The engine uses the smaller of the 22 because a simulation frame must both exist as a buffer and be usable by the compute shader. If either limit is smaller than the requested packed frame, the grid cannot be supported in that packing format. This is why very large grids may need narrower packing or a row count reduced by 11 even when the GPU still has free VRAM.

Simulation buffers use 22 full packed grid buffers plus fixed overhead. Recording buffers use a chunk GPU buffer plus a staging ring:

simulationVRAM=2frameBytes+fixedOverheadBytesrecordingVRAM=chunkFrameCapacityframeBytes(1+stagingRingSize)\begin{aligned} \texttt{simulationVRAM} &= 2\cdot\texttt{frameBytes}+\texttt{fixedOverheadBytes} \\ \texttt{recordingVRAM} &= \texttt{chunkFrameCapacity}\cdot\texttt{frameBytes}\cdot\left(1+\texttt{stagingRingSize}\right) \end{aligned}

The staging ring size is 33, so recording reserves 11 chunk buffer plus 33 staging buffers when recording is available.

VRAM classes shown by the app:

  • Simulation: GPU memory for the current simulation buffers and fixed engine overhead.
  • Recording: GPU memory for the recording chunk buffer and staging ring.
  • Budget: an estimated budget derived from WebGPU buffer limits and the engine buffer plan, not actual physical VRAM.

#Why Packing Matters

Packing is a tradeoff between memory traffic, recording cost, shader work, and supported state count. Lower bits per cell reduce frame bytes, which helps larger grids fit WebGPU buffer limits, keeps recording available, lowers OPFS growth, and makes exports cheaper. As covered in the benchmark conclusions, this matters most while recording and once large grids become memory-traffic bound.

Higher bits per cell support more tribes and can avoid repacking when complex rulesets or snapshots require more states. They also simplify the shader's packing math because fewer cells share each u32 word. That can reduce overhead on smaller non-recording grids, where dispatch, scheduling, and browser/GPU pipeline overhead often matter more than raw frame size.

Game of Life: Tribes · Simulation v1.0.0 · Open source