import { IndirectStorageBufferAttribute } from 'three/webgpu'; import type { ComputeNode, Renderer } from 'three/webgpu'; import type { ComputeBatch } from '../Utils/ComputeBatch.js'; import type { TSLNode, TSLStorageNode, TSLUintNode } from '../types/tsl.js'; type SortBoolNode = TSLNode<'bool'> & { select(whenTrue: unknown, whenFalse: unknown): SortUintNode; and(other: unknown): SortBoolNode; }; type SortUintNode = TSLUintNode & { toVar(): SortUintNode; add(value: unknown): SortUintNode; sub(value: unknown): SortUintNode; mul(value: unknown): SortUintNode; bitAnd(value: unknown): SortUintNode; bitXor(value: unknown): SortUintNode; shiftLeft(value: unknown): SortUintNode; shiftRight(value: unknown): SortUintNode; min(value: unknown): SortUintNode; max(value: unknown): SortUintNode; div(value: unknown): SortUintNode; equal(value: unknown): SortBoolNode; lessThan(value: unknown): SortBoolNode; greaterThanEqual(value: unknown): SortBoolNode; assign(value: unknown): void; addAssign(value: unknown): void; }; export interface ComputeSubgroupRadixSortOptions { values?: TSLStorageNode<'uint'> | undefined; keyBits?: number | undefined; /** * Atomic uint storage whose first element holds the live entry count. When set, only * [0, live) is sorted (indirect dispatch), and entries past it are left untouched. */ countBuffer?: TSLStorageNode<'uint'> | undefined; /** * Caller-owned scratch buffers (each holding at least `count` entries). Every scratch * entry is written before it is read, so the owner may reuse them between sorts. */ scratchKeys?: TSLStorageNode<'uint'> | undefined; scratchValues?: TSLStorageNode<'uint'> | undefined; /** * Caller-owned indirect dispatch arguments for bounded sorts, holding * `[ceil(live / elementsPerWorkgroupFor(count)), 1, 1]` before every sort. Skips the * sorter's own one-thread prepare kernel when the owner already derives the count. */ dispatchArgs?: IndirectStorageBufferAttribute | undefined; } /** * Reports whether the renderer's device can run the subgroup radix sorter: the * `subgroups` feature plus a minimum subgroup width of 32 (the scatter's shared * leader tables are sized for at most 8 subgroups per 256-thread workgroup). */ export declare function supportsSubgroupRadixSort(renderer: Renderer): boolean; /** * LSD radix sort over uint32 keys with 8-bit digits: a clear/histogram/scan/ * scatter dispatch quartet per pass instead of the 2-bit sorter's dozen-plus * passes, with subgroup ballots providing the scatter's stable in-tile ranking. * 16-bit keys sort in 2 passes, 24-bit in 3, 32-bit in 4. * * The full buffer is sorted every call; culled tails carry all-ones sentinel * keys and stably sort past the live range, matching the gaussian sorter * contract without indirect dispatch. * * @class ComputeSubgroupRadixSort * @short Subgroup-accelerated 8-bit-digit radix sort * @category Compute * @tags Compute, Sort, WebGPU, TSL, Subgroups */ export declare class ComputeSubgroupRadixSort { keysBuffer: TSLStorageNode<'uint'>; valuesBuffer: TSLStorageNode<'uint'> | null; countBuffer: TSLStorageNode<'uint'> | null; count: number; keyBits: number; passCount: number; initialized: boolean; timestampContexts: Array; _keysScratch: TSLStorageNode<'uint'> | null; _valuesScratch: TSLStorageNode<'uint'> | null; _externalKeysScratch: TSLStorageNode<'uint'> | null; _externalValuesScratch: TSLStorageNode<'uint'> | null; _histogram: TSLStorageNode<'uint'> | null; _dispatchArgs: IndirectStorageBufferAttribute | null; _externalDispatchArgs: IndirectStorageBufferAttribute | null; _prepareDispatch: ComputeNode | null; _passes: ComputeNode[][]; _copyBack: ComputeNode | null; _frameBatch: ComputeBatch | null; _renderer: Renderer | null; /** Entries consumed per workgroup for a sort of `count` entries (the size crossover below). */ static elementsPerWorkgroupFor(count: number): number; constructor(keysBuffer: TSLStorageNode<'uint'>, options?: ComputeSubgroupRadixSortOptions); /** Per-frame kernels in submission order, for owners that batch them with their own passes. */ get kernels(): ComputeNode[]; /** Live entry count clamped to capacity: the count buffer when bounded, else the constant. */ _liveCount(): SortUintNode; get _elementsPerThread(): number; get workgroupCount(): number; init(renderer: Renderer): void; _digitOf(key: TSLUintNode, shift: number): TSLUintNode; _buildPrepareDispatch(): ComputeNode; _buildScan(): ComputeNode; _buildPass(shift: number, fromKeys: TSLStorageNode<'uint'>, toKeys: TSLStorageNode<'uint'>, fromValues: TSLStorageNode<'uint'> | null, toValues: TSLStorageNode<'uint'> | null): ComputeNode[]; _buildCopyBack(): ComputeNode; compute(renderer: Renderer): void; dispose(): void; } export {};