WebGPU学习(五): 现代图形API技术要点和WebGPU支持情况调研(WebGPU)

网友投稿 956 2022-06-07


大家好,本文整理了现代图形API的技术要点,重点研究了并行和GPU Driven Render Pipeline相关的知识点,调查了WebGPU的相关支持情况。

另外,本文对实时光线追踪也进行了简要的分析。这是我非常感兴趣的技术方向,也是图形学的发展方向之一。本系列后续文章会围绕这个方向进行更多的研究和实现相关的Demo。

上一篇博文:
WebGPU学习(四):Alpha To Coverage

本文内容

  • 前置知识
  • 技术要点
  • 并行
    • Multiple Queues
    • 同步
    • 多线程
  • 内存管理
  • 延迟渲染
    • Defer Shading
    • Textureless Defer Render
  • GPU Driven Render Pipeline
    • Approaching zero driver overhead
    • GPU Cull
    • GPU Lod
  • Hybrid Render For Real-time Ray Tracing
    • 混合渲染
    • 如何使用WebGPU学习和实现Ray Tracing
    • 学习资料
  • 其它
    • Bindless Texture
    • Virtual Texture
    • Tessellation
    • Mesh Shader

前置知识

  • 现代图形API包括哪些API?
    包括DX12、Vulkan、Metal

  • MVP是什么?
    是WebGPU的最小可用版本。
    在1.0版本发布前,先发布MVP版本。

技术要点

下面依次进行分析:

并行

为了提高多核CPU和GPU的利用率,现代图形API充分支持了并行。

并行包含下面的技术要点:

Multiple Queues

介绍

为了提高GPU利用率,可以将不同种类的任务对应的command buffer提交到3种队列中:
graphics queue
copy queue
compute queue

不同队列的任务能够在GPU中并行执行,从而实现Async Compute,提高利用率。

参考资料
Multi-engine synchronization

WebGPU支持情况

根据Multiple Queues skeleton proposal,MVP只支持单队列:

what single queue is exposed in the MVP

同步

介绍

有3个技术可以实现CPU与GPU之间以及GPU内部的同步:

  • semaphores

我不了解它,它应该是用来同步队列的

  • memory barrier

它用来避免GPU因为资源依赖关系造成等待,以及避免CPU和GPU之间发生Race Condition。

现代图形API更加底层,以前GPU做的同步工作也交给了图形程序员,更加灵活的同时也加重了程序员的负担。

参考资料
Breaking Down Barriers

  • fence

它用来在CPU和GPU之间同步。

WebGPU支持情况

  • semaphores

因为目前只支持单队列,所以不需要它

  • memory barrier

大家都表示memory barrier不容易实现,所以barriers由WebGPU帮我们做了(参考Memory barriers investigations、Memory Barriers portability、The case for passes -> Synchronization and validation),我们只需要给WebGPU一些提示(如指定buffer的usage)

  • fence

支持以计数的方式实现fence。

参考资料
TimelineFences

多线程

介绍

可以在线程中执行现代图形API相关的渲染任务:

  • 在线程中更新资源
    如更新buffer

  • 并行地编译shader

  • 并行地创建pipeline state

  • 在线程中创建command buffer

WebGPU支持情况

有两种方法实现多线程:

  • 通过OffscreenCanvas API,实现主线程与渲染线程分离

根据Rendering to OffscreenCanvas on non-yielding workers:
WebGPU支持OffScreenCanvas API,但是目前Chrome不能使用它。

  • 创建worker,在worker中执行WebGPU相关的渲染任务

Create a proposal for multi-worker中提出了WebGPU如何在worker中执行渲染任务:

1.Asynchronous texture & buffer uploads
2.Asynchronous shader compilation
3.Asynchronous pipeline state creation
4.Using MTLParallelRenderEncoder
5.Each thread in a thread pool records into its own command buffer

根据Minutes for GPU Web meeting 2019-08-05 -> Multi threading:
其中的1,2,3正在实现中;
4, 5会最终实现(没有说好久实现);

根据我目前的调查:
1.shader编译和创建pipeline state目前是同步的,还不是异步的。
2.在WebGPU 规范中,GPUTexture,GPUBuffer,GPUDevice,GPUComputePipeline,GPURenderPipeline,GPUShaderModule是Serializable的,意味着可以传给worker。
那是不是现在已经可以在worker中使用它们,从而实现1,2,3呢?需要进一步验证!

扩展阅读

引擎对于多线程的封装:
Parallelizing the Naughty Dog Engine using Fibers
Destiny’s Multi-threaded Renderer Architecture

内存管理

介绍

与memory barriers类似,现代图形API需要程序员自己管理GPU的资源。

参考资料
Memory Management in Vulkan™ and DX12

WebGPU支持情况

根据WebGPU as low level graphics API:

WebGPU compares closest to Metal (probably since Apple is the one that originally proposed it)--both don't require manual memory management while DX12 and Vulkan do

不需要手动管理memory,WebGPU会帮我们管理

延迟渲染

defer shading

包括两个步骤:
第一个pass遍历gameObjects,创建gbuffer;
第二个pass遍历lights,使用gbuffer计算光照。

相对于前向渲染,它的优点是只在屏幕上出现的像素中计算SHADING,从而使复杂度由O(M * N)将为O(M) + O(N)

WebGPU支持情况

因为支持MRT(多渲染目标),所以支持延迟渲染。

值得一提的是两个优化的方向:

  • 优化内存访问

在Investigation: Managing on-chip memory中提到:
第一个pass创建gbuffer后,gbuffer的数据会从on-chip内存移到主内存中;
第二个pass读取gbuffer时,将gbuffer的数据从主内存移到on-chip内存。

gbuffer的数据来回移动,造成了性能损失。
因此在Add render sub-passes中,建议增加render的子pass,在子pass中读取gbuffer,从而实现在创建和读取gbuffer期间,gbuffer的数据一直在on-chip内存中。

Minutes for GPU Web meeting 2019-10-28也讨论了这一点。

WebGPU可能会在extension中支持这个优化。

  • 针对tile-based defer shading,使用compute shader,在第二个pass中剔除光源,剩余的光源参与光照计算

正如DirectX 11 Rendering in Battlefield 3所说:

Hybrid Graphics/Compute shading pipeline:
› Graphics pipeline rasterizes gbuffers for opaque surfaces
› Compute pipeline uses gbuffers, culls lights, computes lighting &
combines with shading
› Graphics pipeline renders transparent surfaces on top

参考资料

延迟着色法
Optimizing tile-based light culling
DirectX 11 Rendering in Battlefield 3

textureless defer render

介绍

在defer shading的第一个pass中,我们将gameObject的几何数据(如Position, Normal等)和材质贴图数据(如从diffuse map中获得的diffuse)存到gbuffer中。

有了bindless texture的支持,我们可以对此进行优化:

  • gbuffer不再存储材质贴图的数据,而是存储uv和material id。在第二个pass中,shader根据它们去获取对应材质贴图texture的数据

这样做的优点是:
1.减少了gbuffer的大小
2.只在可见的像素中,采样texture的数据,减少了采样次数

这样做也存在一些问题,不过都是可以解决的:
具体可以参考什么是deferred material shading?是否会在未来流行开来?:

1.多材质如何做deferred shading?总不能每个像素做动态分支,一个一个判断吧。有人提出了做tile把像素区块合并,然后一次性dispatch,性能会高很多。至于vgpr,sgpr,lds占用率之类需要通盘考虑,偏向一边都会影响性能。
2.结果SSAO,SSR之类的post effect还是需要用到normal,roughness之类的g-bufffer信息。应用上还是需要权衡利弊。

以及参考Deferred Texturing:

What about mip levels, or derivatives?

  • gbuffer不存储几何数据,而是存储primitive ID。在第二个pass中,接收vertex data,在每个可见像素上执行vertex shader

具体可以参考Deferred Texturing -> Defer All The Things:

It stores only primitive IDs in its G-buffer; then in a later pass, it fetches vertex data, re-runs the vertex shader per pixel (!), finds the barycentric coordinates of each fragment within its triangle, interpolates the vertex attributes, then finally samples all the textures and does the shading work.

WebGPU支持情况

根据本文后面bindless texture的分析,目前WebGPU不支持bindless texture
或许可用texture 2d array代替bindless texture,从而使用WebGPU实现textureless defer render

参考资料

Deferred Texturing
什么是deferred material shading?是否会在未来流行开来?
BINDLESS TEXTURING FOR DEFERRED RENDERING AND DECALS
Modern textureless deferred rendering techniques

GPU Driven Render Pipeline

介绍

这个技术应该是在[Siggraph15] GPU-Driven Rendering Pipelines中提出来的。它的思想是把渲染任务从CPU端移到GPU端,减少CPU与GPU的同步和数据传输,实现1个draw call就渲染整个场景,从而提高GPU的利用率。

优点

  • GPU更细粒度的Visibility

  • 不需要在CPU和GPU之间来回传递数据

应用场景

  • 绘制大量的静态物体

  • 绘制人群

  • 绘制模块化半自动生成内容

主要步骤

离线处理
1.分解gameObject的mesh为多个cluster

参考GPU Driven Pipeline — 工具链与进阶渲染

CPU
1.对gameObject进行粗粒度的frustum cull

2.使用persistent map buffer,准备GPU的数据

可以按照数据的类型,创建多个mapped buffer(如一个buffer存储人群的数据,另一个buffer存储所有静态物体的数据)

3.使用virtual texture处理texture

所有的texture数据一次性全部准备好,只绑定一次texture

4.用indirect draw发起multi draw call,提交mapped buffer

WebGPU目前不支持multi draw,因此需要发起多个draw call,每个draw call使用indirect draw提交对应的mapped buffer

GPU
1.对gameObject进行frustum cull和occlusion cull

2.对gameObject的cluster进行frustum cull和occlusion cull

3.修改index buffer,生成新的indices数据

根据Proposal: Run all index buffers through a compute shader validator:

I'm inclined to propose that WebGPU MVP doesn't support index buffers changed on the GPU, since this is quite a bit of headache, but eventually we can do that.
...
In an actual 1.0 release we'll absolutely need to support GPU-generated indices, there is no question here.

WebGPU MVP不会支持在GPU端修改index buffer,1.0版本会支持。

4.multi draw call

根据ExecuteIndirect investigation:

In order to issue draw calls on the CPU, there must be a synchronization point where the CPU waits for the GPU update to complete. This is particularly devastating for WebGPU, where if the CPU has to wait for the GPU, you miss your implicit present and now you're a frame late. Being able to issue these commands on the GPU directly means the rendering and update steps can be in sync.

在GPU端发起draw call可以去掉“CPU和GPU同步”的开销。

However, making it an extension seems valuable.

可能会在WebGPU extension中支持该特性。

总结

GPU Driven Render Pipeline可以一次性取得所有mesh data,通过virtual texture可以取得所有texture,意味着整个场景只需要一次drawcall

参考资料


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java编译器API简介(java编写api接口)
下一篇:18.DjangoRestFramework学习一之restful规范、APIview、解析器组件、Postman等(django rest framework apiview)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~