迁移到即将推出的 WebGPU 不仅仅意味着切换图形 API。这也是迈向网络图形未来的一步。但是,通过准备和理解,这种迁移会变得更好——本文将帮助您做好准备。
小伙伴们好,我是 Dmitrii Ivashchenko,是 MY.GAMES 的平台建筑项目流程师。在本论文中,我们公司将专题讨论 WebGL 和将发行的 WebGPU 范围内的差异性,并将简绍怎么样筹备项目流程来搬迁。
内容概述 WebGL 和 WebGPU 的用时表 WebGPU 的当前动态和在发展壮大 高层领导基本特征相互影响 默认化• WebGL:两排文建模方法• WebGPU:仪器建模方法 项目和管材• WebGL:应用程序• WebGPU:排水管 职业装• WebGL 1 中的制服女• WebGL 2 中的职业装• WebGPU 中的降服 渲染器• 渲染器语言:GLSL 与 WGSL • 统计数据的类型更• 结构设计• 指数函数声明范文• 内装置功能模块• 调色器变为 承诺一定的差异 纹理、纹路• 视口三维空间• 剪集地方 WebGPU 显示信息与方法技巧• 很大效率地缩减您用的管道网数目。 • 晚到使用通道• 的使用宣传包 简概
WebGL 和 WebGPU 的时间表 WebGL 与许多其他 Web 技术一样,其根源可以追溯到很久以前。要了解转向 WebGPU 背后的动力和动机,首先快速浏览一下 WebGL 开发的历史会很有帮助:
OpenGL 桌面版 (1993) OpenGL 桌面版首次亮相。 WebGL 1.0 (2011) :这是 WebGL 的第一个稳定版本,基于 OpenGL ES 2.0,该版本本身于 2007 年推出。它为 Web 开发人员提供了直接在浏览器中使用 3D 图形的能力,而无需额外的插件。 WebGL 2.0 (2017) :在第一个版本六年后推出,WebGL 2.0 基于 OpenGL ES 3.0 (2012)。该版本带来了许多改进和新功能,使网络上的 3D 图形更加强大。
近几余载,我们对新的设计 API 的兴致增多,这样的 API 为搭建专业人员具备了更加多的保持力和方便性:
Vulkan (2016) :由 Khronos 小组创建,这个跨平台 API 是 OpenGL 的“继承者”。 Vulkan 提供对图形硬件资源的较低级别访问,从而允许高性能应用程序更好地控制图形硬件。 D3D12 (2015) :该 API 由 Microsoft 创建,专用于 Windows 和 Xbox。 D3D12 是 D3D10/11 的后继版本,为开发人员提供了对图形资源更深入的控制。 Metal (2014) :Metal 由 Apple 创建,是 Apple 设备的专有 API。它的设计考虑到了 Apple 硬件上的最佳性能。
WebGPU 的当前状态以及未来发展 现在的我们,从手机版本 113 逐渐开始,WebGPU 可经过 Google Chrome 和 Microsoft Edge 挑选器在 Windows、Mac 和 ChromeOS 等诸多平台子上使用的。再创新高在赶快的将会将苹果支持 Linux 和 Android。
一下有的是些已是不扶持(或提供了实验室性不扶持)WebGPU 的引挚:
Babylon JS :完全支持 WebGPU。 ThreeJS :目前处于实验支持状态。 PlayCanvas :正在开发中,但前景非常光明。 Unity :2023.2 alpha 版本中宣布了非常早期的实验性 WebGPU 支持。 Cocos Creator 3.6.2 :正式支持 WebGPU,使其成为该领域的先驱之一。 Construct :目前仅在 Windows、macOS 和 ChromeOS 的 v113+ 中受支持。
考虑一下到这一點,缓冲间到 WebGPU 或大约为那样缓冲间安排楼盘虽然是在赶紧的明年采取相应的及时的步聚。
高层概念差异 叫我们大家从展开化展开,我看看 WebGL 和 WebGPU 间的很多精致举例不同。
初始化 当开使运行空间图形 API 时,一号步是缺省化中用沟通互动的主女朋友。 WebGL 和 WebGPU 两者之间的这样的过程 进行有差异,一个设计常有这些层次性独到之处。
WebGL:上下文模型 在 WebGL 中,这样的构造函数被又称“下上文”,它本身上象征了在 HTML5 画布重元素上制图的界面。修改这样的下上文无比简洁明了:
const gl = canvas.getContext('webgl');
WebGL 的左右侧文其实上与某的画布有关系联。这预兆着如何您必须在个画布上效果图渲染,则将必须个左右侧文。
WebGPU:设备模型 WebGPU引用一个叫做“产品”的新性质。该产品代表着您将与之交流互动行为的 GPU 抽象、。初使化的时候比 WebGL 中的动下繁杂很多,但它给予了很多的方便性:
const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice(); const context = canvas.getContext('webgpu'); context.configure({ device, format: 'bgra8unorm', });
该型号的优缺其中之一是一种台装置可能在好几个画布上渲图,还可能在不会画布上渲图。这展示了增加的灵敏性;举例,一款 装置可能的控制好几个对话框或两排文章中的渲图。
计划和管道 WebGL 和 WebGPU 象征了管理工作和机构图行供水管道的有差异形式。
WebGL:程序 在WebGL中,其主要留意的是渲染器软件。该软件结合在一起了三角形的中心和场面描写渲染器,定议了三角形的中心应怎么改变或者每项清晰度应怎么渲染。
const program = gl.createProgram(); gl.attachShader(program, vertShader); gl.attachShader(program, fragShader); gl.bindAttribLocation(program, 'position', 0); gl.linkProgram(program);
在 WebGL 中創建软件程序的操作步骤:
创建着色器 :编写并编译着色器的源代码。创建程序 :将编译好的着色器附加到程序中,然后进行链接。使用程序 :在渲染之前激活程序。数据传输 :数据传输到激活的程序。
此进程不能灵活机动的形状操纵,但也有机会很僵化而且轻松出现异常,相当是针对小型僵化的工作。
WebGPU:管道 WebGPU 构建了“管路”的产品概念,而是分次的步骤。该管路一方面相结合实际了渲染器,还相结合实际了其余讯息,那些讯息在 WebGL 中被加入为形态。于是,在 WebGPU 中新创建管路看着更有难度:
const pipeline = device.createRenderPipeline({ layout: 'auto', vertex: { module: shaderModule, entryPoint: 'vertexMain', buffers: [{ arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] }], }, fragment: { module: shaderModule, entryPoint: 'fragmentMain', targets: [{ format, }], }, });
在 WebGPU 中创立pvc管道的流程:
着色器定义 :着色器源代码的编写和编译,类似于在 WebGL 中的完成方式。管道创建 :将着色器和其他渲染参数组合到管道中。管道使用 :管道在渲染之前激活。
WebGL 将草图大师渲染图的不同等层面简单,而 WebGPU 则来尝试将很多等层面芯片封装到1个对方中,使程序比较控制板块化和灵活多变。 WebGPU 不太像 WebGL 那么样简单管理系统显色器和草图大师渲染图模式,反而是将所有的内部组合成到另一个排水管对方中。这令该的过程 比较可预计另外不容易不成功:
制服 统一标准变量名作为可供那些上色器事例便用的常量数据分析。
WebGL 1 中的制服 在基本的WebGL中,我们能够直接通过API调用来设置uniform
变量。
GLSL :
uniform vec3 u_LightPos; uniform vec3 u_LightDir; uniform vec3 u_LightColor;
JavaScript :
const location = gl.getUniformLocation(p, "u_LightPos"); gl.uniform3fv(location, [100, 300, 500]);
此方法很简单,但需要对每个uniform
变量进行多次 API 调用。
WebGL 2 中的制服 随着 WebGL 2 的到来,我们现在能够将uniform
变量分组到缓冲区中。尽管您仍然可以使用单独的统一着色器,但更好的选择是使用统一缓冲区将不同的统一分组为更大的结构。然后,您可以立即将所有这些统一数据发送到 GPU,类似于在 WebGL 1 中加载顶点缓冲区的方式。这具有多个性能优势,例如减少 API 调用并更接近现代 GPU 的工作方式。
GLSL :
layout(std140) uniform ub_Params { vec4 u_LightPos; vec4 u_LightDir; vec4 u_LightColor; };
JavaScript :
gl.bindBufferBase(gl.UNIFORM_BUFFER, 1, gl.createBuffer());
要在 WebGL 2 中绑定大型统一缓冲区的子集,您可以使用称为bindBufferRange
的特殊 API 调用。在 WebGPU 中,有类似的东西称为动态统一缓冲区偏移量,您可以在调用setBindGroup
API 时传递偏移量列表。
WebGPU 中的制服 WebGPU 为我们提供了一种更好的方法。在这种情况下,不再支持单独的uniform
变量,并且工作仅通过uniform
缓冲区完成。
工作组SL :
[[block]] struct Params { u_LightPos : vec4<f32>; u_LightColor : vec4<f32>; u_LightDirection : vec4<f32>; }; [[group(0), binding(0)]] var<uniform> ub_Params : Params;
JavaScript :
const buffer = device.createBuffer({ usage: GPUBufferUsage.UNIFORM, size: 8 });
当今 GPU 更很爱将动态数据初始化到两个大块中,而并非是大多一小块中。不就能够每天都继续有个和继续帮定小抗震区,反而是考虑的有个两个大抗震区并将其有所差异个部分使用于有所差异的画出启用。这类的办法就能够显得加强功能。
WebGL 更为操作命令式,两遍就会进行就会更改局部变量的状态,并关键在于尽机会简洁明了。同双角度,WebGPU 的关键是更为指向物体并重视起来资源量重点用,因此的提升速率。
是由于措施的差异化,从 WebGL 过度到 WebGPU 已经看了起来很难。虽然,从过度到 WebGL 2 最为中方法流程是可以细化您的生活中。
着色器 从 WebGL 转化到 WebGPU 既须要修该 API,还须要修该渲染器。 WGSL 规范性主要是使这类接合平整且最直观,还维持如今的 GPU 的吸收率和性能参数。
着色器语言:GLSL 与 WGSL WGSL 为了更好地已成为 WebGPU 和该机几何体 API 两者之间的桥梁施工。与 GLSL 不同之处,WGSL 看上来更烦杂些许,但空间结构还是很记住。
这纹理素材染色器的举例:
GLSL :
sampler2D myTexture; varying vec2 vTexCoord; void main() { return texture(myTexture, vTexCoord); }
工作组SL :
[[group(0), binding(0)]] var mySampler: sampler; [[group(0), binding(1)]] var myTexture: texture_2d<f32>; [[stage(fragment)]] fn main([[location(0)]] vTexCoord: vec2<f32>) -> [[location(0)]] vec4<f32> { return textureSample(myTexture, mySampler, vTexCoord); }
数据类型比较 下表表明了 GLSL 和 WGSL 中根本统计资料类形和向量统计资料类形的更:
从 GLSL 调整到 WGSL 显示了对更要从严的型和资料程度的厘清确定的期盼,这不错不断提高源代码易用性并限制误区的也许性。
结构 宣称成分的日语语法也情况了变现:
GLSL:
struct Light { vec3 position; vec4 color; float attenuation; vec3 direction; float innerAngle; float angle; float range; };
工作组:
struct Light { position: vec3<f32>, color: vec4<f32>, attenuation: f32, direction: vec3<f32>, innerAngle: f32, angle: f32, range: f32, };
传入显式日语语法来证明函 WGSL 设备构造中的字符串提出了对挺高画面清晰度度的盼望,并还简化了朝着色器中统计数据设备构造的谅解。
函数声明 GLSL :
float saturate(float x) { return clamp(x, 0.0, 1.0); }
工作组SL :
fn saturate(x: f32) -> f32 { return clamp(x, 0.0, 1.0); }
改进 WGSL 中方程的英语的语法发生变化了严正声明和取到值方案的统一的,使编码十分一样和可預測。
内置功能 在 WGSL 中,诸多默认设置 GLSL 方程已被重称或编辑。比如:
重排列顺序WGSL中的原带函数值不但抽象化了这些的公司名称,而使这些相对正确性,这需要简单生疏另外的图行API的发掘人士的淡入流程。
着色器转换 对于那方面那方面年度计划将创业项目从 WebGL 改变为 WebGPU 的人策略而言,非常重要的是要了解一些工具软件可能定时将 GLSL 改变为 WGSL,如 **[Naga](//github.com/gfx-rs/naga /)**,那就是某个使用在将 GLSL 改变为 WGSL 的 Rust 库。在 WebAssembly 的让下,它和可能在手机流览器中普通 的工作。
下例是 Naga 支技的端点:
约定差异 纹理 变迁后,您或许会遇着翻折图片方式的神秘礼物。那一些这些年将选用软件程序从 OpenGL 移植后到 Direct3D(或反而亦然)的人已要面对过在这个經典大问题。
在 OpenGL 和 WebGL 的前后左右选文,线条一般来说以起和结束清晰度分属于左下角的方式英文启动。但在真正软件中,大多数研发者会从左上起启动全部图片搜索,若想致使全部图片搜索翻折不正确。只不过,你这个不正确需要借助其它各种因素来赔偿费,最中改善事情。
与 OpenGL 多种,Direct3D 和 Metal 等体统过去上用到右上角用作纹理图片的起始点。满足到此类步骤针对于一些设计的人员来说就尽管是最形象的,WebGPU 的创造者决定了应遵循此类方式。
视口空间 若您的 WebGL 编码从帧储存区选分辩率,请最好的准备,因此 WebGPU 用到不一样的经纬度轴系。您几率可以应用领域比较简单的“y = 1.0 - y”进行来更正经纬度轴。
剪辑空间 当设计人会面临相亲对象比预想更早被抗拉或消失不见的间题时,这一般来说与强度域的差别相关的英文。 WebGL 和 WebGPU 内的不一样就在于它们的怎么定位视频编辑空間的强度依据。 WebGL 采用从 -1 到 1 的依据,而 WebGPU 采用从 0 到 1 的依据,相仿于 Direct3D、Metal 和 Vulkan 等任何平面原型 API。作出此影响是是因为采用 0 到 1 依据的两个优势之处,这部分优势之处是在采用任何平面原型 API 时出现的。
将模型位置转换为剪辑空间的主要责任在于投影矩阵。调整代码的最简单方法是确保投影矩阵输出结果在 0 到 1 的范围内。对于使用 gl-matrix 等库的用户,有一个简单的perspective
方案:您可以使用perspectiveZO
;类似的函数可用于其他矩阵运算。
if (webGPU) { // Creates a matrix for a symetric perspective-view frustum // using left-handed coordinates mat4.perspectiveZO(out, Math.PI / 4, ...); } else { // Creates a matrix for a symetric perspective-view frustum // based on the default handedness and default near // and far clip planes definition. mat4.perspective(out, Math.PI / 4, …); }
同时,有的时候您或者某个共有的投射引流单位分块矩阵,且不可变更其源。在这状态下,要将其改换为 0 到 1 的条件,您可不可以将投射引流单位分块矩阵与另某个调整强度条件的引流单位分块矩阵预乘。
WebGPU 提示与技巧 现如今,我国来座谈某些选用 WebGPU 的表示和秘诀。
最大限度地减少您使用的管道数量。 在使用的给水管愈多,情况下更换就愈多,的性能就越差;这可以非是一项鸡毛蒜皮,实际考量于您的基金来自五湖四海哪。
提前创建管道 构建管线并尽快操作它有会会起用处,但不小编建议那样做。相反的,构建尽快回到并开使在有差异线程上事业的变量。当您操作管线时,做好序列应该等候待除理的管线构建做好。这有会会会造成非常严重的耐热性事情。是为了制止本身情况报告,请确保在构建管线和第一回操作管线中空出一部分耗时。
或者,更好的是,使用create*PipelineAsync
变体!当管道准备好使用时,承诺就会解决,不会出现任何停顿。
device.createComputePipelineAsync({ compute: { module: shaderModule, entryPoint: 'computeMain' } }).then((pipeline) => { const commandEncoder = device.createCommandEncoder(); const passEncoder = commandEncoder.beginComputePass(); passEncoder.setPipeline(pipeline); passEncoder.setBindGroup(0, bindGroup); passEncoder.dispatchWorkgroups(128); passEncoder.end(); device.queue.submit([commandEncoder.finish()]); });
使用渲染包 效果图实时突出图包是再次记下的、有些的、可重复安全使用安全使用的效果图实时突出图缓冲区。同旁内角能够 蕴含大很多数效果图实时突出图操作命令提示符(出了布置视口这些的操作命令提示符),同时能够 在稍后为实际的效果图实时突出图缓冲区的一有些“重播”。
const renderPass = encoder.beginRenderPass(descriptor); renderPass.setPipeline(renderPipeline); renderPass.draw(3); renderPass.executeBundles([renderBundle]); renderPass.setPipeline(renderPipeline); renderPass.draw(3); renderPass.end();
突出包可不可以与正规突出区域强制性同时实行。两遍束缚包实行很久和此后,突出区域的情形一定会解锁为默认设置值。这般担任若是要才能减少作图的 JavaScript 开销。无论怎样通过那类的方法,GPU 性都维持保持不变。
概括 过渡性到 WebGPU 不但仅预示着调成平面原型 API。这也是跨入 Web 平面原型发展的一大步,组合了多种多样平面原型 API 的实现目标实用功能和实践操作。在这种转化需要对技巧和企业理念变动有明白的认知,但利弊是确实不错的。
有用的资源和链接: 作者:Alain Galvan Brandon Jones 的 WebGL + WebGPU 聚会 - 2023 年 7 月