Sorting 模块 API 参考
本参考文档涵盖了 src/sort/ 导出的公共接口层。它对应了 GPU 基数排序器 (GPURSSorter) 的 TypeScript 实现,以及与渲染器和预处理器共享的接口。
导出项 (Exports)
// src/sort/index.ts
export interface ISorter { ... }
export interface SortedSplats { ... }
export { GPURSSorter, HISTOGRAM_WG_SIZE, RS_HISTOGRAM_BLOCK_ROWS } from './radix_sort';
export type { PointCloudSortStuff } from './radix_sort';
接口 (Interfaces)
ISorter
排序器实现的契约接口。
interface ISorter {
createSortStuff(device: GPUDevice, numPoints: number): SortedSplats;
recordSort(sortStuff: SortedSplats, numPoints: number, encoder: GPUCommandEncoder): void;
recordSortIndirect?(sortStuff: SortedSplats, dispatchBuffer: GPUBuffer, encoder: GPUCommandEncoder): void;
}
大多数调用者会与具体的 GPURSSorter 交互,但渲染器通过此接口存储排序器,以便在测试时替换为其他实现。
SortedSplats
interface SortedSplats {
numPoints: number;
sortedIndices: GPUBuffer;
indirectBuffer: GPUBuffer;
visibleCount?: number;
[key: string]: any; // 实现特定的上下文
}
PointCloudSortStuff 扩展了此接口,增加了 GPURSSorter 所需的额外缓冲。
PointCloudSortStuff
interface PointCloudSortStuff extends SortedSplats {
num_points: number; // 兼容性的别名
sorter_uni: GPUBuffer; // GeneralInfo 存储缓冲
sorter_dis: GPUBuffer; // 间接调度 (Indirect dispatch) 缓冲
sorter_bg: GPUBindGroup; // 基数排序管线绑定组
sorter_bg_pre: GPUBindGroup; // 预处理绑定组
sorter_render_bg: GPUBindGroup; // 渲染器绑定组
internal_mem: GPUBuffer;
key_a: GPUBuffer;
key_b: GPUBuffer;
payload_a: GPUBuffer;
payload_b: GPUBuffer;
}
GPURSSorter 类
class GPURSSorter implements ISorter {
static async create(device: GPUDevice, queue: GPUQueue): Promise<GPURSSorter>;
createSortStuff(device: GPUDevice, numPoints: number): PointCloudSortStuff;
recordSort(sortStuff: SortedSplats, numPoints: number, encoder: GPUCommandEncoder): void;
recordSortIndirect(sortStuff: SortedSplats, dispatchBuffer: GPUBuffer, encoder: GPUCommandEncoder): void;
recordResetIndirectBuffer(indirectBuffer: GPUBuffer, uniformBuffer: GPUBuffer, queue: GPUQueue): void;
static createRenderBindGroupLayout(device: GPUDevice): GPUBindGroupLayout;
static createPreprocessBindGroupLayout(device: GPUDevice): GPUBindGroupLayout;
}
GPURSSorter.create(device, queue)
- 异步工厂方法,探测几种子组 (subgroup) 大小 (16, 32, 16, 8, 1)。
- 为每个候选方案构建所有计算管线 (
zero,histogram,prefix,scatter_even,scatter_odd)。 - 使用
recordSort运行testSort(排序 8,192 个浮点数),以确保配置在当前适配器上正常工作。 - 返回配置好的排序器,如果没有配置成功则抛出异常。
createSortStuff(device, numPoints)
- 分配键 (key) / 负载 (payload) 的乒乓缓冲、内部暂存缓冲,以及为
numPoints(向上取整到 3840 对齐块)调整大小的GeneralInfo+ 间接缓冲。 - 构建三个绑定组:
sorter_bg(基数排序 Pass)、sorter_bg_pre(预处理器)和sorter_render_bg(渲染器)。 - 返回一个可以针对每个点云缓存的
PointCloudSortStuff实例。
recordSort(sortStuff, numPoints, encoder)
- 记录
zero -> histogram -> prefix -> scatter过程,显式使用从numPoints派生的工作组数量。 - 主要用于自测试或已知键数量的简单路径。
recordSortIndirect(sortStuff, dispatchBuffer, encoder)
- 同样的 Pass,但使用
dispatchBuffer(通常是sorter_dis)间接调度zero、histogram和两个 scatter 入口点。 - 直接调用
recordPrefixHistogram,因为前缀和总是使用单个工作组计数。 - 由渲染器使用;预处理负责在排序开始前写入
dispatch_x的最终值。
recordResetIndirectBuffer(indirectBuffer, uniformBuffer, queue)
- 将零写入间接调度缓冲和
GeneralInfo的第一个 dword (keys_size)。 - 在预处理之前调用,以便后续的原子增量从已知状态开始。
静态布局辅助方法 (Static layout helpers)
createRenderBindGroupLayout向顶点/计算阶段暴露sorter_uni和payload_a(在渲染器中为@group(1))。createPreprocessBindGroupLayout向预处理暴露sorter_uni,key_a,payload_a, 和sorter_dis(@group(2))。
支持结构体 (Supporting structs)
GeneralInfo
interface GeneralInfo {
keys_size: number; // 由预处理写入的可见 splat 数量
padded_size: number; // 向上取整到 3840 倍数的键数量
passes: number; // 对于 32 位键始终为 4
even_pass: number; // 由 scatter_even 处理的 Pass 的位掩码
odd_pass: number; // 由 scatter_odd 处理的 Pass 的位掩码
}
作为存储缓冲存储在 sorter_uni 中。排序后,渲染器将 keys_size 复制到绘制间接缓冲 (draw indirect buffer) 中。
IndirectDispatch
预处理每处理 256 * 15 个 Splat 就递增一次 dispatch_x。排序器将此结构用于 dispatchWorkgroupsIndirect 调用,渲染器稍后在发出间接绘制时共享同一缓冲。
示例
```ts const sorter = await GPURSSorter.create(device, device.queue); const sortStuff = sorter.createSortStuff(device, totalPoints);
// 在预处理前重置计数器 sorter.recordResetIndirectBuffer(sortStuff.sorter_dis, sortStuff.sorter_uni, device.queue);
// ... 预处理将深度键写入 sortStuff.key_a / payload_a ...
const encoder = device.createCommandEncoder(); sorter.recordSortIndirect(sortStuff, sortStuff.sorter_dis, encoder); device.queue.submit([encoder.finish()]);
// 在渲染 Pass 中使用 pass.setBindGroup(1, sortStuff.sorter_render_bg); pass.drawIndirect(drawIndirectBuffer, 0);