export interface SharedTileRingBuffers { header: SharedArrayBuffer; data: SharedArrayBuffer; } export interface SharedTileRingViews { header: Int32Array; buffer: BigUint64Array; capacity: number; } // Header indices export const TILE_RING_HEADER_WRITE_INDEX = 0; export const TILE_RING_HEADER_READ_INDEX = 1; export const TILE_RING_HEADER_OVERFLOW = 2; export function createSharedTileRingBuffers( capacity: number, ): SharedTileRingBuffers { const header = new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT); const data = new SharedArrayBuffer( capacity * BigUint64Array.BYTES_PER_ELEMENT, ); return { header, data }; } export function createSharedTileRingViews( buffers: SharedTileRingBuffers, ): SharedTileRingViews { const header = new Int32Array(buffers.header); const buffer = new BigUint64Array(buffers.data); return { header, buffer, capacity: buffer.length, }; } export function pushTileUpdate( views: SharedTileRingViews, value: bigint, ): void { const { header, buffer, capacity } = views; const write = Atomics.load(header, TILE_RING_HEADER_WRITE_INDEX); const read = Atomics.load(header, TILE_RING_HEADER_READ_INDEX); const nextWrite = (write + 1) % capacity; // If the buffer is full, advance read (drop oldest) and mark overflow. if (nextWrite === read) { Atomics.store(header, TILE_RING_HEADER_OVERFLOW, 1); const nextRead = (read + 1) % capacity; Atomics.store(header, TILE_RING_HEADER_READ_INDEX, nextRead); } buffer[write] = value; Atomics.store(header, TILE_RING_HEADER_WRITE_INDEX, nextWrite); } export function drainTileUpdates( views: SharedTileRingViews, maxItems: number, out: bigint[], ): void { const { header, buffer, capacity } = views; let read = Atomics.load(header, TILE_RING_HEADER_READ_INDEX); const write = Atomics.load(header, TILE_RING_HEADER_WRITE_INDEX); let count = 0; while (read !== write && count < maxItems) { out.push(buffer[read]); read = (read + 1) % capacity; count++; } Atomics.store(header, TILE_RING_HEADER_READ_INDEX, read); }