2021-WebGLWebGPU,网页图形的全新时代

WebGLWebGPU,网页图形的全新时代

正在看这篇文章的你,是否也写过WebGL?或者,是以WebGL作为自己的主要工作?十年来,我一直从事WebGL相关工作,切身体会到了WebGL强大但又弱小的双生像,但WebGPU的出现让我看到了曙光,我甚至认为——WebGPU替代WebGL成为未来的网页图形技术已经是不可改变的事实。

看完接下来的内容,你将明白我为什么会有这样的观点,也将认识到从现在就开始学习WebGPU的必要性,最后,我还给出了一些学习路径和建议,希望能帮助你更快速地上车。另外,这次演讲的幻灯片也是用WebGPU写的,你可以在文末点击「阅读原文」找到幻灯片的代码和线上版。

WebGL,明日黄花

有人会问,为什么又来一个WebGPU,是WebGL不好用了吗?WebGL好用还是不好用,这个问题十分复杂,我们先看一看WebGL的发展历史,然后再分析它在当前时代下遇到的瓶颈。

可能很多人都不知道WebGL最早的“始作俑者”是谁,书里也没有写。大概是2006年的时候,一个叫做Vladimir Vukićević 的美籍塞尔维亚工程师,在即将到来的HTMLCanvas标签上做了一个个人项目,用Canvas标签实现了OpenGL的原型,他把这个项目叫做Canvas3D。这个项目被他的雇主Mozilla和很多其他浏览器厂商注意到了,被认为很有前途,于是他们就开始继续往下做这件事情,于是就有了WebGL

WebGL&OpenGL,好一对难兄难弟

2011年的时候,WebGL 1.0标准被正式推出,随后的故事就进入了一个尴尬的境地。因为WebGL 1.0推出之后,大家发现它还有很大的进步空间,于是工作组很快就开始着手制定WebGL 2.0标准。但足足过去五六年时间之后,WebGL 2.0才在2017年被正式发布,同时也开启了自己的蹉跎岁月。

在一开始的时候,GoogleMozilla都同步支持了WebGL 2.0,但是你会发现这里面少了一个非常重要的Player——Apple,它一直没有宣布对WebGL 2.0的支持,直到两个月之前,也就是今年的920号,Apple才说我们开始支持WebGL 2.0了,但这个时候黄花菜都凉了。

所以说,WebGL经历了一个非常悲催的发展阶段。

WebGL现在已经很老了,它很老的原因不光是因为它存在的时间长,也是因为它的标准完全是继承自OpenGL ES的,而OpenGL ES的设计理念可以追溯到1992年,甚至更早的一些理念是从1980年代的IRIS GL时代传下来的,那个时候你们可能都没有出生。

这些古老的理念,WebGL到现在还在使用,而这些理念其实已经非常不符合今天的GPU的工作原理了,然后就造成了一些问题。我们前端开发者用WebGL写起来很快乐,大家可以在Three.js的官网看到有非常多使用WebGL创造的美妙的网页,但是对于那些浏览器的开发者而言,他们就非常头疼,这给他们的工作带来了非常大的不便。

举一个例子,WebGL至今不可以做并行计算,或者说它做并行计算非常麻烦。大家虽然可能没有做过,但应该也听说过,在今天的人工智能时代,我们要去训练模型,做各种神经网络,都是用GPU来进行计算的,但是WebGL不支持这种计算,这就很麻烦。曾经业界有公司想要给WebGL增加这个功能,但这件事就非常的困难。到底有多困难,我们等一会儿会讲到。

WebGL过得已经够惨了,它的老大哥OpenGL还要更惨一点,这个标准现在基本上已经没有人使用了。在最早的时候,包含WebGL在内的HTML5为什么能够战胜Flash?很重要的一个原因是Apple掌门人乔布斯的力挺,力挺各种Open的标准,他们认为这个是行业的未来。

例如当年在苹果手机上唯一支持的图形框架就是OpenGL ES,所有早期的苹果设备上的游戏都依赖于OpenGL ES(比如愤怒的小鸟、切水果;但在乔布斯去世之后,Apple就抛弃了OpenGL,自己开发了全新的图形框架Metal

WebGL的拥有者——Khronos Group,也逐渐淡化了OpenGL这一WebGL标准的的基础。你可能对Khronos不熟悉,前端开发一般比较熟悉的是W3C、TC39。Khronos Group这个组织是一个图形界的标准组织,WebGLOpenGL就是它旗下的标准。在抛弃OpenGL之后,他们全力打造了现在的明星产品Vulkan

所以,几乎现在所有的操作系统都不再把OpenGL作为首要支持了,AppleMac系统甚至明确表示了这一点,他们所有的OpenGL应用都会转成Metal运行。

另外还有一点大家可能不知道,我们所写的任何一行WebGL代码,在浏览器底层实际上有99%的可能并不是由OpenGL绘制,而是通过Angle这个库转化成本地代码,也就是说,它在Windows电脑上是用DirectX绘制的,在Apple上是用Metal绘制的。

今天,OpenGL已经不适用于高端图形领域,尤其是AAA游戏开发,它已经到了可以安享晚年的时候了。不过在其他的一些行业,比如低端和嵌入式图形领域,科研之类的,OpenGL依旧在发光发热。而OpenGL SC也会继续服务于军工、航天、车机等安全关键行业。就好像虽然WebGPU会代替WebGL成为网页图形新标准,但是WebGL依然会继续存在一样,在一些特殊领域发光发热。

图形行业格局:从龙虎斗到三足鼎立

那么现在的图形行业是一个什么样的情况呢?

最早的时候,图形行业是OpenGLDirect3D两者龙虎斗,现在,开发者有了更多的选择——DirectX 12、Vulkan、Metal并列为三大现代图形框架,全面释放了GPU的可编程能力,让开发者可以最大限度地自由操控GPU

这里还有一个对比,做过WebGL的可能都知道Blinn Phong这些早期的传统材质,而当时基于物理渲染的PBR材质还被视为次世代高端技术,只有在XboxPlayStation上才可以用,但它现在已经是遍地开花,所有的Three.jsBabylon.js等等都是以PBR为主要标准材质的。

还有就是光线追踪技术,你所看到的那些优秀的电影的表现、电视特效都是由光线追踪技术来渲染生成的,这个技术对算力有极大的要求。

我可以举一个例子《星际穿越》这个电影是由新西兰的维塔工作室负责特效制作的,其中的黑洞镜头每一帧需要渲染100小时,也就是说,你看到每秒钟的黑洞镜头,需要超过100天的渲染时间。而现在我们藉由NVIDIA RTX显卡的专门硬件处理单元甚至可以做到实时光线追踪。

再说一个变化,当年的GPU实时渲染还只能作为产品草稿图和预览图,因为它噪点非常多,但是随着基于深度学习的人工智能降噪技术的提出,GPU渲染一夜翻身,直接迈步成为生产环境可用的可靠渲染方式之一。

《古墓丽影 8》

《古墓丽影 9》

所以说,图形行业在这几年的发展和我们前端一样都是非常迅猛的。我们举一个简单的例子,就是古墓丽影这款游戏《古墓丽影8》和《古墓丽影9》只差一个版本,但是一个是2008年,一个是2013年,从它们身上完全可以看出图形发展的两个不同的阶段。从图上你可以看出,2008年的《古墓丽影8》的场景非常简单,也不够细致,光影效果也比较一般,尤其是劳拉,她身上的建模是非常生硬的,但是到了2013《古墓丽影9》里的背景已经非常细致了,它的右上角还用了体积云的绘制技术,虽然从这张图中可能看不清劳拉的背影,但是她皮肤的质感、人物的动作已经和真人非常相近了,尤其是她的头发,玩游戏的可能都知道,被玩家称为“海飞丝”技术,它可以让每一根发丝随着物理的引擎的驱动来进行真实的摆动。

图形工业发展如此之快,WebGL显然已经不再适合我们在未来的网页图形开发,所以一个新的标准WebGPU诞生了。

WebGPU,网页图形的未来

WebGPU的目的在于提供现代3D图形和计算能力,和WebGL不同首先在于它不再由Khronos这个图形界的标准组织拥有,而是回归到了我们前端程序员的快乐老家W3C,由GPU for the Web社区工作组开发。第二个不同是,它不再继承或者完全仿制某一个已经实现的本地图形标准,而是参考了VulkanMetalD3D12API设计理念,对标这些图形框架研发了一个全新的跨平台的高性能图形接口。

WebGPU的诞生:大厂角力的结果

WebGPU的诞生过程实际上就是大厂角力的一个过程。

2016年,Google发现WebGL存在一些问题,于是就提出了一个新的提案叫WebGL Next,说我们要再做一个精确的图形API。然后,其他的厂商也纷纷跟进,Mozilla、Apple、Opera都提出了自己的概念。

这个时候,Apple起名部的工作人员立了大功,他们向W3C提交了一个叫做WebGPU的提案,这个提案好不好咱们另说,但是WebGPU这个名字是非常好的,让人耳目一新,于是W3C决定采纳这个名字作为未来新标准的命名,并且成立工作组来做WebGPU的工作。

因为这个名字是Apple起的,所以最后只有Apple的提案进入了他们“gpuweb-proposals”的代码仓库,不过为了避免重名造成的误解和冲突,Apple最初的那个提案的名字被改为了WebMetal

看到W3C接纳了Apple的提案,Mozilla不甘心,转而又向Khornos Group提交了一个基于Vulkan的命名为WebGL Next的提案,但这已经是WebGL的最后一搏了。

这个时候,大家都很迷茫——我们是跟着W3C走还是跟着Khornos走呢?最后,浏览器厂商用脚投票,站到了WebGPU这边。2018年的时候,Google Chrome团队宣布开始着手WebGPU标准的实现工作,这也在事实上宣布了WebGPU的胜出和WebGL的终结——不会再有WebGL 3.0WebGL Next了。

随后,WebGPU标准进入了一个茁壮成长的阶段,因为WebGL让人们知道在网页上开发图形是可行的,可以说,WebGPU标准是站在WebGL的肩膀上发展的,WebGL给它的成长打好了基础。于是,工作组的人员在那几年中密切开会,制定了新的标准。到了今年的9月份,我们已经可以在ChromeSafari上对WebGPU进行大规模测试了,你只需要填写申请表获取一个Token,然后在HTML文件的标签中填入此TokenChrome浏览器就会为此网页开启WebGPU支持。

根据WebGPU工作组的计划,他们准备在今年年底发布WebGPU 1.0标准,但是现在已经是12月了,显然留给工作组的时间不多了。

WebGPU到底是什么

那么WebGPU到底是一个什么东西?

首先,WebGPUWebGL不一样的是,WebGPU是一个精确的图形API。什么叫做精确?举一个简单例子,当你在WebGL里绘制一些东西的时候,你说gl = canvas.getContext(‘webgl’),你获得了一个上下文,你可以在里面画东西,但这个上下文或者背后发生了什么?显卡是如何反应的?浏览器跟显卡是如何协同工作的?这些东西你都不知道。但是WebGPU不一样,它完全开放了整个显卡能力,你要向显卡发送命令去控制显卡,它不再是画东西的一个库,而是一个利用GPU的库。

第二,WebGPU的设计标准的起点非常高,它的野心绝对不只是在网页上做图形。WebGPU一开始就是和Vulkan、Metal、Direct3D 12等更高性能的本地图形标准对标的,意思是说我的WebGPU就像一个HAL硬件抽象层一样,我只要对应这套标准,未来不仅可以在网页运行,甚至也可以在嵌入式、在服务器运行,就像WebAssembly一样。WebAssembly本意是在网页运行,但是现在在服务器上运行也有非常好的发展前途。WebGPU也有这样的野心,它想把自己这个东西去做大,所以它的核心的关键词是 「跨平台的高性能图形标准

第三,WebCPU终于开始支持GPU Compute Shader,并且是把GPU通用计算作为首要支持。

第四,WebGPU包含一个全新的专为Web设计的、人类可编写的着色器语言——WGSL(WebGPU Shading Language,这里我会稍微展开解释下为什么它要包含这个东西。我们传统的基于字符串形式的着色器代码,对于浏览器厂商来说是非常头疼的,如果你写过GLSL,可能就知道它是一个类C的语言,它的编译器也像C一样,而每一个厂商的驱动都不一样,最终很难保持跨端的一致性。同时,人们发现,Vulkan标准提出的SPIR-V的着色器标准,是一个非常好的基于汇编的一个二进制的着色器程序,所以WebGPU也是对标它的。

WebGPU的标准里面就写的很明白,就是说我这里面着色器所有的东西都要一一对应于SPIR-V里的东西,每一个东西都要在SPIR-V里头找到一个相应的映射。那么有一个问题,既然我们完全对标SPIR-V,那我们为什么不直接用SPIR-V呢?这是因为Apple跟前面提到的Khronos,他们之间有一个关于知识产权上的官司,所以大家可以发现Apple一直在消极对待Khronos的各种各样的产品,所以在WebGPU工作组中,Apple就明确发言我绝对不会在自己的标准中使用任何Khronos的技术,于是没有办法,工作组就只能重新设计了这样一个着色器语言。

最后,WebCPU没有状态机的机制了,它是面向对象的编程,新增了很多的对象,增加了异步支持,并且改善了验证机制。

WebGPUWebGL性能对比

WebGL

WebGPU

让我们看一下复杂场景的渲染性能,这个场景中有1000棵树,它们不是使用实例化绘制的,而是每一棵树都有一个draw call,所以一个场景我要有1000多个draw call。如果使用WebGL进行绘制的话,你可以看到在我的电脑上使用2070显卡只能跑到21FPS,而且每一帧的CPU时间需要44毫秒,但是同样用WebGPU来处理,在我的电脑上可以跑到123帧,每一帧的CPU时间只有0.1毫秒,这个是WebGPUWebGL最大最显著的性能上的差距。

let gl = canvas.getContext("webgl");

gl.createShader(type);
gl.shaderSource(shader, sourceCode);
gl.compileShader(shader);
gl.createProgram();
gl.attachShader(program, shader);
gl.linkProgram(program);
gl.useProgram(program);
gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, dataView, gl.STATIC_DRAW);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(mode, 0, size);

另外就是一个代码上的差距,观察我们用WebGL原生API绘制的过程,你可以发现所有的东西的起点都在于Canvas;然而这是一件很不可思议的事情,就是我即使不需要画什么东西,我也需要创建一个Canvas元素,这个操作对于我们这个前端可能是无感知的,但是对于浏览器开发者来说我要新建一个DOM元素,就要给它增加所有它需要有的东西,一旦DOM元素崩溃了,浏览器要处理所有这些事情,对于开发者而言后面的事情就会变得非常复杂。

let adapter = await navigator.gpu.requestAdapter();
let device = await adapter.requestDevice();
let context = canvas.getContext('webgpu');
let context.configure({ ... });
let commandEncoder = device.createCommandEncoder();
let renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
let renderPipeline = await device.createRenderPipelineAsync(pipelineDescriptor);
renderPassEncoder.setPipeline(renderPipeline);
renderPassEncoder.drawIndexed(indexCount, 1, 0, 0, 0);
renderPassEncoder.endPass();
device.queue.submit([ commandEncoder.finish() ]);

但是WebGPU不是这样,WebGPU的入口是navigator.gpu,你可以从这里获取到一个显卡,再从显卡获取到一个设备,而中间的Canvas有没有是可选的。

如果你单纯只是想用显卡做一些事情,不想把它绘制在屏幕上,你完全可以不用新建Canvas元素,整个代码实例我们后面还会详细讲一下,所以我们这里就略过。

多进程的浏览器架构

多进程浏览器

WebGPU除了对前端开发好之外,还对谁好呢?当然是浏览器的开发厂商,他们终于可以痛快地去写他们的代码了,这是因为现在的浏览器基本都是一个多线程的架构。大家开发的时候可能经常会打开任务管理器看资源消耗,你可以看到浏览器经常不是只有一个进程,而是有非常多的进程在跑着。但是现在的Chrome浏览器有一个缺点,它把所有的进程名都设定为同一个名字,所以你也不知道这些进程到底是干啥的。而新版在Windows11Edge浏览器做了一个改变,它会标明每个进程的名字,告诉你每个进程是干啥的,你可以在这张图里看到有浏览器进程,有GPU进程,有处理崩溃的Crashpad进程等等。我相信Chrome可能也会改一下。

多进程浏览器

这是整个浏览器的一个大概框架图,比如我开了4个标签页,整个浏览器是跑在browser进程里的,每个标签页都有自己的渲染进程。如果你想要安装一些扩展,比如说去广告的扩展,这些扩展会跑在扩展进程里。同时你看到这有一个广告,这个广告实际上是跑在一个独立的渲染进程里的,这主要是基于安全问题而考虑的。然后,中间视频需要编辑,可能要跑一个插件,那插件又有自己的进程,最左边就是我们关心的地方,这里有很多的视频,这些视频可能是MP4格式x264编码的,浏览器可能要借助显卡驱动来进行硬件解码,这些东西都会跑到GPU的进程里面去。

所以说当你在WebGPU中,在JavaScript里新建了一个ArrayBuffer,你想把它最后传到GPU里是要过好几层关卡的。首先在内容进程中的CPU读到了ArrayBuffer,要把它放到共享内存里,通过共享内存让GPU进程的CPU可以看到它,GPU进程中的CPU再把它放到可以映射到GPU的缓存中,最后GPU再去从映射缓存里拷贝到自己的显存中,然后再去进行后续的操作。

因此,实际上在WebGPU的编程模型中,有两条时间线,就像平行宇宙、平行时空一样,一条时间线是内容时间线,一条时间线是GPU设备的时间线。比如说当你在内容进程,也就是你的JavaScript代码里写create buffer的时候,实际上这个buffer还没有被GPU建立,它只是通知了GPU说我要创建一个buffer,顺利的情况下你可以这样去往下做,但是如果错误的情况下就比较麻烦了。因为GPU报错的时候,你的CPU是不知道的,你并不知道buffer创建失败了,但是好在WebGPU给我们提供了非常好的错误处理机制,让你在开发、调试,包括产品上线之后的埋点遥测阶段都可以非常清楚地知道客户端发生了什么事情。

万物皆Promise

其实,你可以把WebGPU开发理解为“万物皆Promise”,理解成面向未来的编程,就是所有都是Future,每一个WebGPU对象都是一个Promise,都是异步过程,相应操作都被外包到刚才所说的GPU进程中,然后在那实际上才是同步的。还有就是编程的时候一定要清楚地意识到每一个对象代表的含义,当你在GPU中创建了一个buffer,它可能只占你的CPU内存中的150字节,但实际上它可能在GPU中占了一个GB的显存,这种事情也是有可能发生的。

还有一个问题就是通过这样的一个映射,我们不再在CPU端做验证,取而代之的是,所有的验证都会放到GPU端去做,这样做的好处就是提升了运行效率。WebGL之所以那么慢,就是因为WebGL的验证机制非常差劲,当然,这也是因为历史原因造成的。

所以说在用WebGPU编程的时候,你的脑子可能会自我精神分裂成两个时间线,去注意两个时间线里不同的进程,同时结合你自己的前端的任务控制机制,包括异步、宏任务、微任务等等,包括你使用的前端框架的生命周期来做编程开发。

WebGPU开发体验,好

下面我们来讲一下WebGPU的开发体验。

WebGPU的开发体验还是非常不错的,我在这次演讲中用到的PPT的背景就是用WebGPU写的着色器效果,这个效果其实是非常复杂的,而且现在WebGPU没有多线程,我只是把它跑在主线程上,但是看起来渲染性能也还挺好。

简单来说首先就是大量的步方法,就像刚才说的你需要掌握Promise;第二它有很好的TypeScript支持,官方提供类型定义文件;另外它有一个全新WGSL语言,你需要去学习,这个语言的语法非常怪异,而且现在显然还是有缺陷的,社区和工作组每天都在提新的设计修改意见,它是一个有点类似于RustTypeScript的缝合怪,如果你的项目有大量的以前的着色器代码,不想把它翻译成WGSL,你也可以回滚到GLSL,比如,你可以预先把它编译成刚才所说的符合SPIRV的二进制代码;最后就是你可以尽情使用所有新的浏览器特性,因为它会跑在未来的浏览器里面。

[[block]]
struct Uniforms {
    [[size(64)]]uPMatrix: mat4x4<f32>;
    [[size(64)]]uMVMatrix: mat4x4<f32>;
};
[[group(0), binding(0)]]
var<uniform> uniforms: Uniforms;
[[stage(vertex)]]
fn main (
    [[location(0)]] aVertexPosition : vec3<f32>
) -> [[builtin(position)]] vec4<f32> {
    return uniforms.uPMatrix * uniforms.uMVMatrix * vec4<f32>(aVertexPosition, 1.0);
}

上面这个就是WGSL语言写的一个很简单的着色器,你可以看到它的变量名称后面跟了冒号,然后再是类型,这点很像TypeScript,并且出现了泛型,而它下面的这个函数fn,一个单箭头指向的语法也很像Rust,所以说它就是这么一个缝合怪,它现在的语言的标准也在不断地修改。

// 获取硬件设备
let adapter = await navigator.gpu.requestAdapter();
let device = await adapter.requestDevice();
// 可以用 Canvas,也可以不用 Canvas,还可以用很多 Canvas;用的话就把 Canvas 与设备相连
let context = canvas.getContext( 'webgpu' );
let context.configure( { ... });
// 创建命令编码器,所有 GPU 指令都是通过它发给 GPU 的
let commandEncoder = device.createCommandEncoder();

// 创建渲染通道、渲染管线、着色器……等等所有你想做的 GPU 指令
let renderPassEncoder = commandEncoder.beginRenderPass( renderPassDescriptor );
let renderPipeline = await device.createRenderPipelineAsync( renderPipelineDescriptor );
renderPassEncoder.setPipeline( renderPipeline );
renderPassEncoder.drawIndexed( indexCount, 1, 0, 0, 0 );
renderPassEncoder.endPass();
// 结束命令编码器并发送到 GPU 设备的指令队列中
device.queue.submit( [ commandEncoder.finish() ] );

下面,我们简单讲一下WebGPU的整个绘制过程。首先就是你要获取一个硬件设备,之前在WebGL中开发者对硬件设备的获取其实是模糊的,你也不太需要关心用户使用的什么显卡,但是现在你可以精确地知道用户安装的是什么显卡。

另外就是Canvas,以前所有的WebGL接口都是绑定在上下文里,但是现在上下文只是负责一个类似于交换链的作用,告诉GPU最后画到哪儿。如果你的应用不需要绘制在屏幕上,你完全不需要新建Canvas。最后一个很重要的概念是命令编码器,command encoder,它的意思是说你可以把你想让GPU执行所有的命令都压到命令编码器里面,让命令编码器把所有的这些命令编在一起,然后存成命令缓存,然后再发送到GPU里面。下面还有一些很重要的概念,就是跟绘制相关的,包括渲染通道,然后渲染管线等等这些。

GPU通用计算

接下来我们讲一下通用计算。这里有一个故事非常有意思,英特尔公司曾经想给WebGL增加通用计算能力,但是当这个被称之为WebGL 2.0 Compute的标准被提出之后,只有Chrome这一个浏览器团队实现了这个标准,而且他们实现起来也相当困难,其他团队根本就没有去实现这个标准。

所以此后,英特尔公司就决定停止开发WebGL 2.0 Compute标准,并把注意力转移到WebGPU上,Google也从Chrome里移除了WebGLCompute支持,所以说这个标准现在已经是名存实亡了。

另外说一句,英特尔公司负责WebGL Compute,包括现在WebGPU Compute部分,很多都是我们中国的工程师。希望能有更多的中国公司参与到网页图形标准的制定中。

在这里,我们举一个简单例子,最简单的排序,我们跟CPU排序做一下对比。CPU排序我们就用JavaScript自带的Array.sort(),而右边的排序我们用的是双调排序,这是一种可以用GPU来做并行计算的排序方法。我们现在有一个数组,这个数组的长度是223次方,也就是数组里有800多万个浮点数。现在,我们要对这个数组进行排序。

排序对比

当我点了排序按钮之后,整个主线程的渲染都已经被卡死了,阻塞了,都停在这儿了,最终我们把它排序完花了10455毫秒。现在,我们再来看一下GPU的排序,大家不要看绝对数值,要看相对数值,GPU只用了394毫秒,它的排序要比整个的CPU排序快非常多。未来GPU通用计算会是一个非常关键的前端领域,像TensorFlow.js等基于做人工智能方向的一些东西,会用它去做非常多的事情,所以它是非常好的一个能力。

网页图形的未来

最后我们来说一下网页图形学的未来。

WebGPU的未来会变成什么样呢?首先,在很快到来的未来,也就是明年,WebGPU工作组的主要工作方向是多线程,他们要为WebGPU增加多线程能力。我们知道现在在WebGL中可以用OffscreenCanvas实现多线程,但是Apple Safari并不支持这个特性,所以实际使用起来会遇到巨大的兼容问题。

还有一个问题,即使使用OffscreenCanvas,它的多线程操作也是比较局限的,因为你需要把整个Canvas的操作全部都转移到唯一的一个Worker里实现。但是WebGPU的多线程相对就非常灵活,你可以把一个Buffer、一个GPU对象简单地通过postMessage()方法发送到任何一个worker,这些worker只要在时间线上没有互斥的操作,它们都可以在不同时间不同的worker里面去对同一个或者多个GPU对象进行操作。所以它的多线程开发体验要比WebGL要好很多。

那在比较远的未来呢?比如说实时光线追踪,这个不是我说的,而是工作组说的,工作组希望在未来他们能够直接调用本地图形,例如DirectX 12,我们能调用本地图形能力来进行一些网页上的绘制,比如说实时光线追踪,这两张图片是当时微软DXR发布的时候的图片,它们不是用CPU离线渲染的那种光线追踪渲染图片,而是一个实时渲染的场景的截图,其中使用了实时光线追踪能力。

实时光线追踪

大家可以设想一下,如果这种质量的实时渲染图形出现在了网页上,我们的网页的生态会变得更加丰富多彩。

下一页