Skip to content

Latest commit

 

History

History
317 lines (156 loc) · 9.04 KB

01 WGSL基础之概念.md

File metadata and controls

317 lines (156 loc) · 9.04 KB

01 WGSL基础之概念

WGSL 是 WebGPU Shading Language 的缩写,它是 WebGPU 的着色器语言。


本文部分知识点来源于


我也是刚开始学习 WGSL,若有讲解错误的地方还请多多担待,更加欢迎留言指正。


开始吧。


概念1:WGSL与GLSL的关系

  1. WGSL 是 WebGPU 配套的着色器语言,其语法更像 Rust
  2. GLSL 是 WebGL 配套的着色器语言,其语法更像 C

补充:

  1. HLSL 是微软 Direct3D 配套的着色器语言

    HLSL 是 High Level Shader Languase 的简写

    DXD12 是 Direct3D 第 12 版本的简写,从 DXD12 版本开始支持 WebGPU

    有些文章会使用 DX12 来代指 DXD12

  2. MSL 是苹果 Metal 配套的着色器语言

    MSL 是 Metal Shading Language 的简写

  3. SPIR-V 是 Vulkan 配套的着色器语言

    SPIR 是 Standard Portable Intermediate Representation 的简写


概念2:WGSL与SPIR-V的关系

  1. SPIR-V 是一种二进制格式
  2. WGSL、GLSL、HLSL 都可以转换成 SPIR-V
  3. SPIR-V 可以转化成 HLSL 和 MSL

概念3:为什么可以横跨3大框架(Vulkan/Metal/DXD12)

  1. 由于 WGSL 可以转化为 SPIR-V
  2. 而 SPIR-V 除 Vulkan外,还可转化运行在 Metal 和 DXD12
  3. 因此 WebGPU、WGSL 可以实现兼容、横跨这 3 种框架与设备

概念4:CPU与GPU参与程度

  1. 在 WebGL/GLSL 中,CPU 几乎参与每一步渲染控制中
  2. 在 WebGPU/WGSL 中,CPU 通过命令编码器可以将多条(所有条)命令一起打包,并交给 GPU 去执行,然后 CPU 就可以空闲了
  3. 由于 WebGPU/WGSL 减轻了 CPU 负担,将图形渲染工作交给了 GPU,因此 WebGPU 相对 WebGL 性能有大幅度提升

概念5:图形渲染与通用计算

  1. WebGPU/WGSL 除了用于 3D 图形渲染,还可以用作 通用计算
  2. 目前深度学习框架 TensorFlow.js 已经支持 WebGPU
  3. 未来会有更多地方 或 框架会用到 WebGPU/WGSL,例如 BIM、CIM、WebXR 等等

概念6:命令式编程、声明式编程、函数式编程

  1. 命令式编程:强调过程,一步一步告诉计算机应该做什么,专注于 “如何去做”

  2. 声明式编程:专注于 “做什么”,而不是 “如何去做”

    比较明显的例子就是 数据库查询,通常只需要输入查询命令就可以得到结果,而无需编写具体的查询过程细节

  3. 函数式编程:把运算过程尽量写成一系列嵌套的函数调用


命令式编程 与 函数式编程 对比示例,假设现在要计算 (1+2)*3/4 的结果。

命令式:

const a = 1 + 2
const b = a * 3
const c = b / 4

强调具体的每一步计算过程,并且会记录过程中的值,也就是说:强调的是具体过程


函数式:

const add = (num1, num2) => {
    return num1 + num 2
}

const multiply = (num1, num2) {
    return num1 * num2
}

const divide = (num1, num2) {
     return num1 / num2
}

const res = divide(multiply(add(1,2),3),4)

将具体过程改造成 不同嵌套函数 之间的调用,计算过程中的某些值并未被记录,只是将某个函数结果当做另外一个函数的参数而已


函数式编程中还有另外一种特殊形式:柯里化,就是把接收多个参数的函数变换为接收单个参数的函数。例如将 fun(a,b,c) 转换为 fun(a)(b)(c) 这种形式。


思考题:

假设有一个数组 let arr = [1,2,3] ,现在想得到该数组中每一项都+1 后的结果,于是代码写成: arr.map(item => item + 1)

请问,这种写法属于以下哪种编程: A:命令式 B:声明式 C:函数式

目前,我的答案是:B

  1. 首先 arr.map() 并没有强调具体的每一步过程,也没有记录过程中每一步的计算结果,因此可以排除 A
  2. 同时,arr.map( item => item + 1) 中也不是将上一次函数结果作为下一次函数的某个参数,不符合函数互相嵌套的形式,因此可以排除掉 C
  3. 那它符合 B 声明式吗?符合,因为 item => item + 1 “强调结果,而不强调过程”

以上纯粹我个人理解和胡说八道,实际上把 arr.map( item => item + 1 ) 说成是 函数式也是说得通的。


网上还有一种说法:函数式属于声明式,是声明式的一种形式


之所以要讲解 命令式、声明式、函数式 的原因是:WGSL 属于 命令式语言,“强调每一步着色过程,一步步详细告诉 GPU 应该做什么”。

额,这一句话不够严谨,实际上着色器(shader)仅仅是 WGSL 的一部分而已

所以通常情况下 .wgsl 中的代码会出现很多 if、for、switch 等代码。

它和我们前端使用的 JavaScript (侧重函数式) 在编写代码时,需要思维习惯上的一些转变。

有条件的,也可以学习一下 Rust、WebAssembly


概念7:静态类型 VS 动态类型

  1. JavaScript 属于动态类型,例如 let a =2; a='hello',变量 a 既可以是数字,也可以是字符串

  2. TypeScript 属于(伪)静态类型

    为什么我说 TS 属于 伪静态类型呢?因为 TS 只是声明变量类型,但不强制变量为某一种固定类型(例如 TS 中允许出现 联合类型、any 等),TS 只是无限模拟 静态类型。

  3. WGSL 属于静态类型,每一个变量、表达式计算结果 都需要明确定义其具体的特定类型

  4. WGSL 不支持类型隐式转换,例如将数字转换为布尔值需要显式转换 或 重新构造

  5. WGSL 仅支持同一类型的元祖,不像 TS 支持不同元素类型的元祖


概念8:并行 & 并发

下面这段知识点来源于 郝伟博士 的一篇文章。示例说明多线程的两组概念:串行VS并行 和 并发VS顺发

https://blog.csdn.net/weixin_43145361/article/details/124701832


并行 VS 串行:

  1. 串行(serial):通常一个大的任务会被拆分成多个小任务(环节、步骤),这些小任务按照顺序依次串联在一起,就像糖葫芦那样。在执行的过程中,各个小任务不能同时进行。他们只能按照顺序依次、逐个执行,直至全部完成,
  2. 并行(parallel):尽管每一个小任务都是串行,但是假设有多个处理单元,每个单元都负责处理某一个小任务,也就是说 同时可以有 N 个小任务在 N 个处理单元进行,就被称为 并行。

小总结:串行 与 并行 强调的是就近使用 几个 处理单元来处理任务。


换句话说:

  1. 假设只能使用 1 个处理单元,那么就是 串行
  2. 假设能够使用 多个 处理单元,那么就是 并行

并发 VS 顺发:

  1. 顺发(sequential):按照顺序一件一件处理(调用),当前任务完成后才会开始触发(处理)下一个任务

    会发生阻塞

  2. 并发(concurrent):当前任务进行中时,就可以随时切换(触发/处理)到另一个任务。

    不会发生阻塞

请注意,并发只是看上去好像 “可以同时进行多项任务”,但实际并发只是强调 “可以在多个任务中来回切换”。

因为无论并发还是顺发,他们都是在单个处理器中进行的。


并行、串行 中的 “行” 背后暗藏着 “执行某件事” 的含义

并发、顺发 中的 “发” 背后暗藏着 “发出任务调度” 的含义


举一个例子:

假设有一个人一边嚼口香糖,一边打电话。

  1. 并行:对于 耳朵 和 嘴巴而言,他们属于两个不同的处理单元,且可以同时进行,因此 耳朵和嘴巴 属于 并行关系

  2. 并发:对于 嚼口香糖 和 说话 而言,这 2 个行为都发生在同一个单元(嘴巴)中,嚼口香糖时不能说话,说话时不能嚼口香糖,但是这 2 个行为之间可以无缝切换,因此这两个行为属于 并发 关系。

    尽管看上去 嚼口香糖 和 说话 好像是同时发生的,但实际上这两个行为只是可以无缝切换而已。

  3. 顺发:整个接听电话的过程为 摁下接听键 > 开始通话 > 自己或对方摁下挂电话键,这几个环节是严格按照顺序发生(执行)的,因此这些行为属于 顺发 关系。


实际关联:

在 WGSL 官方文档 https://www.w3.org/TR/WGSL/ 第 1 章介绍中有这样一句话

“Invocations within a shader stage execute concurrently, and may often execute in parallel. ”

翻译过来就是:着色器阶段中的调用会并发执行,并且通常会并行执行。

额~,如果不了解什么是 并发、并行,那么就完全无法理解上面这句话。


好了,关于 WGSL 的一些基础概念知识点就讲解到这里。

下一节,我们讲解着色器的生命周期。