Skip to content

[功能建议] 新增 destroyBuffer API 用于 GPUBuffer 生命周期管理 #9

Description

@wardenfeng

背景

WebGPU 类目前暴露了 destoryTexture(texture) 用于精细化的纹理生命周期管理,内部调用 WGPUTextureLike.getInstance(...).destroy() 释放显存:

// WebGPU.ts
destoryTexture(texture: TextureLike) {
    WGPUTextureLike.getInstance(this.device, texture).destroy();
}

然而,没有对应的 destroyBuffer API 用于释放 GPUBuffer 资源。

问题

WGPUBuffer 和 WGPUBufferBinding 都注册了清理回调来释放底层 GPUBuffer:

// WGPUBuffer.ts
this.destroyCall(() => {
    gpuBuffer?.destroy();
});

两者都使用 ChainMap(基于 WeakMap 构建)做缓存:

private static readonly map = new ChainMap<[GPUDevice, Buffer], WGPUBuffer>();

问题在于:WeakMap 的 GC 不保证触发 destroyCall 回调。当 JS 包装对象被垃圾回收时,底层的 gpuBuffer.destroy() 可能永远不会被调用,从而导致 GPU 显存泄漏。

这在长期运行、反复创建/销毁带 uniforms 的渲染对象的应用中(例如点云查看器、场景编辑器)尤为严重,buffer 持续累积导致显存稳步增长。

对比

资源类型 公开销毁 API 缓存类型 是否可靠释放
纹理 Texture ✅ destoryTexture ChainMap (WeakMap) ✅ 是(显式调用)
缓冲 Buffer ❌ 无 ChainMap (WeakMap) ❌ 否(依赖 GC)

需求

在 WebGPU 类上新增一个公开方法,用于显式释放 buffer:

// 建议的 API
class WebGPU {
    // 已有
    destoryTexture(texture: TextureLike): void;
    
    // 新增
    destoryBuffer(bufferBinding: BufferBinding): void;
}

实现方式可参照 destoryTexture:

destoryBuffer(bufferBinding: BufferBinding) {
    // 查找缓存的 WGPUBufferBinding 并销毁它
    // (需要像 WGPUTextureLike 一样提供公开的 getInstance + destroy 路径)
}

当前临时方案

目前释放 buffer 的唯一途径是 WebGPU.destroy()(其内部仅 device = null),但这会销毁整个 device 上下文——对于增量式场景更新而言过于粗暴。

环境

  • @feng3d/webgpu:最新版
  • 平台:Chrome 149 / WebGPU

相关建议:也可以考虑暴露 destroyAllBuffers(),或者让 WGPUBuffer/WGPUBufferBinding 公开它们的 destroy()(它们已经从 ReactiveObject 继承了 destroy())。

感谢这个优秀的库!🙏

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions