复杂度不会消失:Bindless 为什么会出现
复杂度不会消失Bindless 为什么会出现上一篇文章讨论了 GPU Driven Rendering。其中一个核心思想是让 GPU 自己组织工作于是GPU Cull GPU LOD GPU Draw Generation逐渐成为现代渲染器的重要组成部分。但当越来越多工作被迁移到 GPU 后。新的问题很快出现。假设一个场景拥有100000 个物体每个物体可能引用Mesh Material Texture当 GPU 开始主动组织渲染时。它首先会遇到一个看似简单的问题这些资源在哪里而 Bindless正是对这个问题的一种回答。最初的资源绑定方式早期图形 API 的思维方式非常直接。CPU 先绑定资源BindTexture(textureA);然后Draw();再绑定BindTexture(textureB);然后Draw();整个流程类似绑定资源 ↓ 绘制 ↓ 绑定资源 ↓ 绘制CPU 始终掌握主动权GPU 不需要知道整个资源世界。因为 CPU 会提前告诉它这次用什么GPU Driven 开始打破这种模型GPU Driven 出现后。情况发生变化。GPU 自己完成Cull LOD Draw Generation此时 GPU 可能决定绘制 Object 17 绘制 Object 203 绘制 Object 5812那么问题来了。Object 5812 使用哪张纹理传统模式下。CPU 已经提前绑定。GPU Driven 模式下。GPU 自己做决定。于是GPU 必须自己查找资源资源访问模型开始改变。Descriptor Heap 开始变大最自然的想法是把所有资源都绑定进去。例如Texture 0 Texture 1 Texture 2 ... Texture N形成一个巨大资源表。Shader 中textureArray[index]直接访问。看起来问题解决了。但实际上。这里发生了一个非常重要的变化。过去CPU 决定资源现在GPU 决定资源资源绑定从静态绑定变成动态索引这正是 Bindless 的核心思想。Bindless 并不是没有绑定这是一个容易产生的误解。很多人第一次看到Bindless会认为完全不需要绑定资源实际上并不是。资源仍然需要注册。Descriptor 仍然需要创建。资源表仍然需要维护。变化的只是什么时候决定使用哪个资源过去Draw Call 之前决定。现在Shader 执行期间决定。绑定并没有消失。只是从 CPU 迁移到了 GPU。为什么复杂度没有消失很多技术的发展都会经历类似过程。最开始Draw Call 太多于是GPU Driven出现。然后资源绑定太多于是Bindless出现。看起来问题被解决了。实际上。复杂度只是换了位置。过去CPU 管理资源绑定现在GPU 管理资源访问于是新的问题开始出现。例如Descriptor 生命周期 Descriptor 分配 Descriptor 回收 资源热重载 资源迁移这些问题并没有消失。只是从渲染代码转移到了资源系统。为什么 Resource Manager 开始变得重要当资源数量达到几千 几万 几十万时。开发者已经无法继续手动管理VkDescriptorSet于是现代引擎开始建立Resource Manager统一维护Texture Buffer Sampler Material用户看到的是TextureHandle底层管理的是Descriptor IndexShader 看到的则是textureTable[index]整个资源系统开始围绕索引运行。这也是为什么现代引擎越来越喜欢Handle而不是Texture*因为 Handle 天然适合映射到资源表。Bindless 与 ECS 的相似之处有趣的是。Bindless 和 ECS 实际上存在相似思想。传统对象模型对象拥有资源例如Mesh ├─ Texture*├─ Material*而 Bindless 更接近资源表拥有资源对象只保存TextureIndex MaterialIndex从直接引用变成间接索引这与Entity ↓ Handle ↓ Storage的 ECS 思想非常接近。因此很多现代引擎最终会同时出现Handle Archetype GPU Driven Bindless它们背后的设计哲学其实非常一致。为什么现代 API 都在走向 Bindless观察近几代图形 API 会发现。大家都在推动类似能力Vulkan Descriptor IndexingD3D12 Resource Binding Tier 3Modern GPU Descriptor Heap原因很简单。资源规模增长速度远快于 Draw Call 数量增长速度。当场景拥有几万个物体 几千种材质 数万张纹理时。传统绑定模型开始越来越难以维持。GPU 需要更自由地访问资源。Bindless 正是这种需求的结果。结语很多人第一次接触 Bindless 时。看到的是textureArray[index]这样的代码。但从架构角度看。Bindless 并不仅仅是一种资源访问技术。它代表着另一种资源管理思维。过去CPU 决定资源 GPU 使用资源现在GPU 决定资源 GPU 使用资源资源绑定并没有消失。Descriptor 也没有消失。复杂度同样没有消失。它只是从Draw Call 组织转移到了资源管理而 Bindless正是现代渲染器在资源规模不断增长之后的一次必然演化。