1. 介绍
本节内容为非标准的
图形处理单元,简称GPU,对于在个人计算中实现丰富的渲染和计算应用程序至关重要。 WebGPU 是将 GPU 硬件能力公开给 web 的一组 API。该API设计自底向上有效地映射到(2014 年后)原生 GPU API。WebGPU 与 WebGL 没有关系,也不对应到 OpenGL ES。
WebGPU 将物理 GPU 硬件视为 GPUAdapter
。 它通过 GPUDevice
对适配器进行连接,GPUDevice
可以用来管理资源,同时设备的 GPUQueue
可以用来执行指令。 GPUDevice
可能有自己的内存,可以高速访问处理单元。 GPUBuffer
和 GPUTexture
是 GPU 内存中的两种物理资源。 GPUCommandBuffer
和 GPURenderBundle
是用来存储用户记录指令的容器。 GPUShaderModule
用来存储 着色器 代码。 其他资源,将按照 GPU 使用 物理资源 的方式进行配置,例如 GPUSampler
或 GPUBindGroup
。
GPU 可以通过将数据导入管线的方式,来执行 GPUCommandBuffer
中编码的指令,这是不易编程时期和可编程时期的混合。 可编程时期,GPU可以运行着色器语言,着色器语言是专为在 GPU 硬件上运行而设计的特殊程序。管线的大部分状态通过 GPURenderPipeline
或 GPUComputePipeline
对象来定义。 不在这些 管线 对象中的状态,是在编码时通过使用指令设置的,例如 beginRenderPass()
或 setBlendConstant()
。
2. 恶意使用注意事项
本节内容为非标准的 本节描述了在 Web 上公开此 API 相关的风险
2.1. 安全
WebGPU 的安全标准与 Web 环境的安全标准一样,同样需要严格执行。实现安全标准的一般做法是在所有指令到达 GPU 之前对其进行严格验证,确保一个页面只能访问该页面自己的数据。
2.1.1. 基于 CPU 的未定义行为
WebGPU 的实现是针对特定的目标平台,将用户提交的工作任务转换为 API 指令。这些API指令的合法使用规则由原生 API 进行明确。(例如,参见 vkCreateDescriptorSetLayout)如果不遵守合法的使用规则,通常不保证 API 指令的执行结果。这称为“未定义行为”,黑客可以利用这种行为来访问没有权限的内存或强制驱动程序执行恶意代码。
为了禁止不安全的使用,任何被用户提交的工作任务,都需要被定义在WebGPU允许的行为范围内。一个 WebGPU 的实现必须验证用户提交的所有工作任务,只有合法的工作任务才能被驱动程序执行。 本文档明确了所有错误场景和异常处理方法。例如,在 copyBufferToBuffer()
的“源”和“目标”中指定具有交叉范围的相同缓冲区,会导致 GPUCommandEncoder
产生错误,并且不会执行后续的其他操作。
请查看 § 21 错误 & 调试 有关报错处理的更多信息。
2.2. 基于 GPU 的未定义行为
WebGPU 着色器 程序由 GPU 硬件内部的计算单元执行。 在原生 API 中,某些着色器指令可能会导致 GPU 上出现未定义的行为。为了解决这个问题,着色器指令集及其定义的行为都是由 WebGPU 严格定义的。 当着色器代码被提供给 createShaderModule()
时, WebGPU 的实现必须在执行任何转换前(到特定于平台的着色器)对代码进行验证。
2.3. 未初始化的数据
通常,分配新内存可能会暴露系统上运行的其他应用程序的剩余数据。为了解决这个问题,WebGPU 会在概念上将所有资源初始化为零,但是如果开发人员手动做了初始化操作,在实际中可能会跳过此步骤。这些需要被初始化的内容包括着色器内的变量和共享工作组中的内存。
清除工作组内存的精确机制可能因平台而异。如果某个平台的原生 API 不提供清除工作组内存的机制,WebGPU 在此平台的实现将对计算着色器的处理转换为: 首先清除所有调用,同步确认所有调用都被清除后,再继续执行开发人员的代码。
2.4. 着色器中的越界访问
着色器程序可以对物理资源进行直接访问(例如,作为 "uniform"
GPUBufferBinding
),或通过纹理单元对物理资源进行访问,这里的纹理单元是指处理纹理坐标转换的固定功能硬件块。API 端的验证只能保证将所有的输入提供给着色器,并且保证这些输入都有正确的用法和类型。
如果没有调用纹理单元,主机 API 端不能保证数据在边界内访问。
为了防止着色器访问了应用程序没有权限的 GPU 内存,WebGPU 的实现可能会在驱动程序中启用特殊模式(称为“鲁棒性缓冲区访问”),这种特殊访问模式保证了着色器的访问在缓冲区边界内。
另一种防止着色器越界访问的方法是,WebGPU 的实现,可以通过插入手动边界检查来转换着色器代码。当采用这种方法时,越界检查仅适用于数组索引。着色器结构的普通字段访问不需要被检查,因为 minBindingSize
的验证在主机端完成。
如果着色器尝试在物理资源边界之外加载数据,WebGPU 的实现可以允许:
-
在资源边界内的另一个位置返回一个值
-
返回带有任意“X”的“(0, 0, 0, X)”的值向量
-
部分丢弃绘制或调度调用
如果着色器尝试在物理资源边界之外写入数据,WebGPU 的实现可以允许:
-
将值写入资源边界内的另一个位置
-
丢弃写操作
-
部分丢弃绘制或调度调用
2.5. 无效数据
将 浮点数 数据从 CPU 上传到 GPU 时,或者在 GPU 上生成浮点数,我们最终可能会得到一个不对应的二进制表示的有效数字,例如无穷大或 NaN(非数字)。 这种情况下的 GPU 行为是受限于 GPU 硬件实现的精度,这里的 GPU 硬件实现是基于 IEEE-754 标准的。 WebGPU 保证引入无效的浮点数只会影响算术计算的结果,不会有其他副作用。
2.5.1. 驱动程序错误
GPU 驱动程序像任何其他软件一样容易出现错误。 如果发生错误,黑客可能会利用驱动程序的错误行为来访问没有权限的数据。为了降低风险,WebGPU 工作组将与 GPU 厂商进行协调,将 WebGPU 一致性测试套件 (CTS) 作为其驱动程序测试流程的一部分进行集成,这和 WebGL 的驱动程序测试方法类似。 WebGPU 的实现将为一些已发现的错误提供规避方法,并在无法规避已知错误的驱动程序上禁用WebGPU。
2.5.2. 定时攻击
WebGPU 通过 Web Workers 进行多线程使用。 因此,WebGPU 的设计是避免用户遭遇到现代的高精度定时攻击。 一些对象,比如 GPUBuffer
或 GPUQueue
,具有同时被访问的共享状态。因此可能会发生竞争条件,类似于多个 Web Workers 同时访问同一个的 “SharedArrayBuffer”,这种情况下线程调度是可见的。
WebGPU 解决这个问题的方法是,只有当跨域隔离规则开启后,再将反序列化(或共享)对象的能力只赋予代理集群中的代理,此限制符合对抗恶意使用“SharedArrayBuffer”的 缓解措施。同样,用户代理也可以序列化代理共享任何句柄以完全防止任何并发。
总结来说,WebGPU 共享状态下可能遭受到的竞争攻击是 SharedArrayBuffer
攻击的一小部分。
WebGPU 还指定了 "timestamp-query"
功能,给 GPU 操作提供高精度计时。 该功能是可选的,一个 WebGPU 的实现可能会只暴露在那些受信任的场景中。 或者,计时查询结果可以由计算着色器处理并对齐到较低的精度。
2.5.3. 行锤攻击
行锤 是利用 DRAM 单元中的状态泄漏来进行的一类攻击。 它可以被用在 GPU 上。 WebGPU 没有任何特定的缓解措施,主要依赖于平台级解决方案,例如减少内存刷新间隔。
2.6. 拒绝服务
WebGPU 应用程序可以访问 GPU 内存和计算单元。 WebGPU 实现可能会限制 应用程序的可用 GPU 内存,以保持其他应用程序的响应。对于 GPU 处理时间,WebGPU 实现可能会设置“看门狗”计时器,以确保应用程序不会导致 GPU 无响应超过几秒钟。这些措施与 WebGL 中使用的措施类似。
2.7. 工作负载识别
在同一台机器上运行的不同程序(和网页)之间,存在共享的受限全局资源,WebGPU 提供对这些资源的访问能力。 基于这些共享资源的使用模式,应用程序可以尝试间接探测这些全局资源是如何受限的,以便推断由其他打开的网页执行的工作负载。这些问题通常与 Javascript 面对的问题类似,例如系统内存和 CPU 执行吞吐量。 WebGPU 不提供任何对此额外的 缓解措施。
2.7.1. 内存资源
WebGPU 暴露了机器全局内存堆中,例如 VRAM,的错误分配能力。通过尝试分配内存资源和检测内存分配是否失败,使系统剩余可用内存的大小(对于给定的堆类型)可以被探测到。
GPU 内部有一个或多个(通常只有两个)内存堆,由所有正在运行的应用程序共享。 当堆耗尽时,WebGPU 将无法创建资源。这些内存堆的分配是可见的,这可能使得恶意应用程序猜测哪些堆被其他应用程序使用,以及这些应用程序从中分配了多少资源。
2.7.2. 计算资源
如果一个站点与另一个站点同时使用 WebGPU,那么这个站点会发现处理一些工作的时间增加了。 例如,如果一个站点不断提交计算工作任务并跟踪队列上工作的完成情况,可能会观察到其他工作任务也开始使用 GPU。
GPU 有许多可以独立测试的部分,例如算术单元、纹理采样单元、原子单元等。恶意应用程序可能会感知到其中一些单元受到压力,并通过分析应力模式来试图猜测另一个应用的工作量。 这与实际 Javascript 的 CPU 执行方式相似。
2.8. 隐私
WebGPU 可以暴露许多关于底层 GPU 架构和设备几何结构的细节。这包括可用的物理适配器,对 GPU 和 CPU 可以使用的资源的许多限制(例如最大纹理大小),以及任何可选的特定于硬件的可用能力。
用户代理没有义务暴露真正的硬件限制,他们完全控制了有多少机器细节可以被暴露。 减少指纹识别的一种策略是分箱,将所有目标平台放入几个 bin 中。 一般来说,暴露硬件限制的隐私影响与 WebGL 的隐私影响相匹配。
默认限制也特意设置得足够宽松,以允许大多数应用程序在不需要请求更高权限的情况下工作。 API 的所有使用都根据请求的限制进行验证,所以实际的硬件功能不会偶然暴露给用户。
2.8.1. 特定于机器的工件
存在于一些特定于机器的光栅化/精度工件和性能差异,他们在 WebGL 中同样也可以观察到的。 这些特定于机器的工件适用于光栅化覆盖和模式、着色器阶段之间变化的插值精度、计算单元调度、以及执行的更多方面。
通常,光栅化和精确指纹在大多数或所有供应商的设备中都是相同的。性能差异比较棘手,但差异也相对较小(与 JS 执行性能一样)。
2.8.2. 机器特定性能
区分用户的另一个因素是衡量 GPU 上特定操作的性能。即使计时精度较低,重复执行操作也可以显示用户的机器在执行特定工作任务下的速度是否很快。这是一个相当常见的向量(存在于 WebGL 和 Javascript 中),但它也是低信号且相对难以真正标准化的。
WebGPU 计算管线公开了对 GPU 的访问,不受固定功能硬件的阻碍。这给唯一设备指纹带来了额外的风险。 用户代理可以采取措施将逻辑 GPU 调用与实际计算单元分离以降低这种风险。
2.8.3. 用户代理状态
本规范没有定义任何额外的用户代理状态。
但是,需要用户代理提供编译缓存给大开销的编译,如 GPUShaderModule
、GPURenderPipeline
和 GPUComputePipeline
。这些缓存对于提高 WebGPU 应用程序在第一次访问加载后的加载时间很重要。
对于规范来说,这些缓存在极其快速的编译中难以辨别,但是对于应用程序来说,很容易衡量 createComputePipelineAsync()
需要多长时间来执行。这可能会跨源泄漏信息(例如“用户是否使用此特定着色器访问了站点”),因此用户代理应遵循 存储分区 中的最佳实践。
系统的 GPU 驱动程序也可能有自己的编译着色器和管线缓存。 用户代理 可能希望尽可能禁用这些,或者采用使 GPU 驱动程序认为它们不同的方法,将每个分区的数据添加到着色器。
2.8.4. 适配器标识符
注意:预计 WebGPU 将公开某些级别的信息,以识别正在使用的 GPU 适配器的类型。 这是指纹信息的潜在来源,但过去使用 WebGL 的经验表明,在某种程度上,有必要使开发人员能够创建健壮的应用程序并有效地响应用户问题。
3. 基本概念
3.1. 公约
3.1.1. 点符号语法
在此规范中,使用了通常在编程语言中被使用的 .
("点符号")语法。短语“Foo.Bar
”的意思是“Foo
中的 Bar
成员”。
在JavaScript中被采用的 ?.
(“可选链操作符”)语法也会用到。短语“Foo?.Bar”意思是,“如果 Foo
为 null
或 undefined
,则结果为 undefined
; 否则,结果返回 Foo.Bar
”。
例如, buffer
是一个GPUBuffer
, buffer?.[[device]].[[adapter]]
的意思是,“如果 buffer
为 null
或 undefined
,则buffer是 undefined
;否则,返回buffer内部的 [[adapter]]
内部的 [[device]]
。”
3.1.2. 内部对象
内部对象是一个概念性的,未暴露的 WebGPU 对象。内部对象追踪一个 API 对象的状态,并且包含了所有潜在的 API 实现。如果一个特定内部对象的状态可以从多个代理中并行地被改变,那么这些改变对于所有代理来说,总是最小的可执行单元。
Note: 一个 "代理" 指一个 Javascript “线程”(即. 主线程,或 Web Worker)。
3.1.3. WebGPU 接口
一个WebGPU 接口是一个封装了内部对象的暴露接口。内部对象的状态通过 WebGPU 提供的接口进行改变。
所有包含 GPUObjectBase
的接口是一个WebGPU 接口。
interface mixin {
GPUObjectBase attribute USVString ?label ; };
GPUObjectBase
有以下属性:
label
, of type USVString, nullable-
标签,在开发工具(比如错误/告警消息,浏览器开发工具,平台调试工具)中被使用,并用来给开发者识别底层内部对象。标签没有特定的格式,所以不能可靠的被机器解析。
在任何情况下,开发者可以自由选择是否使用该标签字段。
GPUObjectBase
有以下内部槽位:
3.1.4. 对象描述符
一个对象描述符包含创建对象需要的信息,通常是通过 GPUDevice
中的某一个 create*
方法创建的。
dictionary {
GPUObjectDescriptorBase USVString label ; };
GPUObjectDescriptorBase
有以下成员:
label
, of type USVString-
GPUObjectBase.label
的初始值。
3.2. 无效内部对象 & 传染无效性
WebGPU 中的对象创建操作在内部是异步的,因此它们不会因异常而失败。相反,返回的对象可能引用有效或无效的内部对象。无效的对象可能永远不会在以后变得有效。一些对象可能在其生命周期内变得无效,而大多数可能仅在创建时才无效。
如果无法创建对象,则对象从创建时就无效。例如,如果对象描述符没有描述有效的对象,或者没有足够的内存来分配资源,就会发生这种情况。
大多数类型的内部对象在创建后不会变为无效,但仍然可能变得不可用,例如 如果拥有设备丢失或销毁
,或者对象具有特殊的内部状态,如缓冲区状态已损坏。
某些类型的内部对象在创建后可能会变得无效;具体来说,比如设备、适配器和命令/传递/捆绑编码器。
GPUObjectBase
对象能与目标对象一起有效被使用:
-
对象 必须为 有效.
-
对象.
[[device]]
必须为 有效. -
对象.
[[device]]
必须等于 目标对象.[[device]]
.
3.3. 坐标系
-
Y轴在标准化设备坐标 (NDC) 中向上:NDC 中的点(-1.0, -1.0)位于NDC的左下角。 此外,NDC中的x和y应介于-1.0和1.0之间(含),而 NDC中的z应介于0.0和1.0之间(含)。NDC中超出此范围的顶点不会引入任何错误,但会被剪裁。
-
Y轴在帧缓冲区坐标、视口坐标和片元/像素坐标中向下:origin(0, 0) 位于这些坐标系中的左上角。
-
窗口/当前坐标匹配帧缓冲区坐标。
-
纹理坐标中的origin(0, 0)的UV表示纹理内存中的第一个纹素(最低字节)。
Note: WebGPU 的坐标系与图形管道中的 DirectX 坐标系相匹配。
3.4. 编程模型
3.4.1. 时间线
本节内容为非标准的
前端有用户代理、后端有 GPU 的计算机系统具有并行工作在不同时间线上的组件:
- 内容时间线
-
与 Web 脚本的执行相关联。 它包括调用本规范描述的所有方法。
在内容时间线上执行的步骤如下所示。 - 设备时间线
-
与用户代理发出的 GPU 设备操作相关联。它包括创建显卡适配器、设备和 GPU 资源及状态对象,从控制 GPU 的用户代理部分的角度来看,这些操作通常是同步操作,但可以存在于单独的操作系统进程中。
在设备时间线上执行的步骤如下所示。 - 队列时间线
-
与在 GPU 的计算单元上执行操作相关。它包括在 GPU 上运行的实际绘制、复制和计算任务。
在队列时间线上执行的步骤如下所示。
在本规范中,当结果值取决于发生在除内容时间线以外的任何时间线上的工作时,将使用异步操作。它们由 JavaScript 中的回调和承诺表示。
GPUComputePassEncoder.dispatch()
:
-
用户通过调用发生在内容时间线上的
GPUComputePassEncoder
方法对dispatch
命令进行编码。 -
用户调用
GPUQueue.submit()
,将GPUCommandBuffer
移交给用户代理,用户代理通过调用操作系统驱动程序在设备时间线上执行低级提交。 -
在队列时间线上,提交由 GPU 调度程序分发到实际计算单元上执行。
GPUDevice.createBuffer()
:
-
在内容时间线上,用户填写一个
GPUBufferDescriptor
,并用它创建一个GPUBuffer
。 -
用户代理在设备时间线上创建一个低级缓冲区。
3.4.2. 内存模型
本节内容为非标准的
一旦在应用程序初始化例程中获得了GPUDevice
,我们可以将 WebGPU 平台描述为由以下层组成:
-
实现规范的用户代理。
-
具有用于此设备的低级原生 API 驱动程序的操作系统。
-
实际的 CPU 和 GPU 硬件。
WebGPU 平台的每一层可能有不同的内存类型,用户代理在实现规范时需要考虑:
-
GPU 驱动程序通常无法访问脚本拥有的内存,例如脚本创建的
ArrayBuffer
。 -
用户代理可能有不同的进程,负责运行内容,以及与GPU驱动程序的通信。在这种情况下,用户代理使用进程间的共享内存来传输数据。
-
专用 GPU 拥有自己的高带宽内存,而集成 GPU 通常与系统共享内存。
大多数物理资源分配在对 GPU 计算或渲染高效的内存类型中。当用户需要向 GPU 提供新数据时,数据可能首先需要跨越进程边界才能到达与 GPU 驱动程序通信的用户代理部分。然后这些数据可能需要对驱动程序可见,因此有时需要复制这些数据到驱动程序分配的暂存内存中。最后,这些数据可能需要被转移到专用 GPU 内存中,从而可能将内部布局更改为对 GPU 进行操作最高效的布局。
所有这些转换都是由用户代理的 WebGPU 实现完成。
Note: 这个例子描述了最坏的情况,而在实践中实现可能不需要跨越进程边界,或者可能能够将驱动程序管理的内存通过 ArrayBuffer
直接暴露给用户,从而避免任何数据复制。
3.4.3. 多线程
3.4.4. 资源使用
物理资源可以和内部使用一起在 GPU 上被使用:
- 输入
- 常量
-
从着色器的角度来看是常量的资源绑定。保留内容。缓冲区
UNIFORM
或纹理TEXTURE_BINDING
允许。 - 存储
-
可写入存储的资源绑定。被缓冲区
STORAGE
或纹理STORAGE_BINDING
允许。 - 只读存储
-
只读存储的资源绑定。保留内容。被缓冲区
STORAGE
允许。 - 附件
-
在渲染过程中用作输出附件的纹理。被纹理
RENDER_ATTACHMENT
允许。 - 只读附件
-
在渲染过程中用作只读附件的纹理。被纹理
RENDER_ATTACHMENT
允许。
纹理可能由单独的mipmap levels和array layers组成,它们可以在任何给定时间以不同的方式被使用。每个这样的纹理子资源都由纹理、mipmap levels和(仅适用于 2d
纹理的)array layer和aspect唯一标识。
我们定义子资源可以是整个缓冲区,也可以是纹理子资源。
强制将对资源的使用仅组合到兼容使用列表中,可以让 API 限制使用内存时可能发生数据竞争的时间。该属性使对 WebGPU 编写的应用程序更有可能在不同平台上运行而无需修改。
通常,当实现以不同于当前使用允许的方式处理使用子资源的操作时,资源会被转换到新状态。 在某些情况下,例如在开放的 GPURenderPassEncoder
中,由于硬件限制,这种转换是不可能的。我们将这些地方定义为使用范围。
主要的使用规则是,对于任何一个子资源,该子资源在一个使用范围内的内部使用列表必须是一个兼容使用列表。
例如,在同一 GPURenderPassEncoder
中绑定相同的缓冲区用于存储和输入将使编码器以及拥有的 GPUCommandEncoder
进入错误状态。这种用法组合不会形成兼容使用列表。
Note: 允许在单个使用范围内出现多个可写存储缓冲区/纹理使用的竞争条件。
提供给 GPURenderPassColorAttachment.view
和 GPURenderPassColorAttachment.resolveTarget
的视图中包含的纹理子资源被视为用作此渲染通道使用范围的附件。
纹理子资源的物理大小是纹理子资源在纹素中的维度,包括可能的额外填充,以在子资源中形成完整的纹素块。
-
对于基于像素的
GPUTextureFormats
,物理大小始终等于采样硬件中使用的纹理子资源的大小。 -
基于块的压缩
GPUTextureFormats
中的纹理始终具有mipmap level 0,其[[descriptor]]
.size
是纹素块大小的倍数,但较低的mipmap level可能不是纹素块大小的倍数,可以使用填充到整数倍。
GPUTexture
,其 [[descriptor]]
.size
为{60, 60, 1},在mipmap level 2 上对 GPUTexture
进行采样时,采样硬件使用{15, 15, 1}作为纹理子资源的大小 ,而其物理大小为 {16, 16, 1},因为块压缩算法只能在 4x4 纹素块上运行。 3.4.5. 同步
对于物理资源的每个子资源,其内部使用的标识集在队列时间线上被跟踪。
在队列时间线上,有一个有序的使用范围序列。 在每个范围的持续时间内,任何给定子资源的内部使用标识集是恒定的。 子资源可以在使用范围之间的边界转换为新的使用。
本规范定义了以下使用范围:
-
在一个通道之外(在
GPUCommandEncoder
中),每个(非状态设置)指令都是一个使用范围(例如copyBufferToTexture()
)。 -
在一个计算通道中,每个调度指令(
dispatch()
或dispatchIndirect()
)都是一个使用范围。 如果一个子资源可以被指令访问,则该子资源在使用范围内“使用”。 在调度中,对于每个绑定组可以被当下GPUComputePipeline
中的[[layout]]
使用,同时该绑定组引用的每个子资源也都在使用范围内“使用”。 状态设置计算通道指令,如setBindGroup(index, bindGroup, dynamicOffsets)
,不直接影响使用范围; 反而,这些指令可以更改在调度指令中被检查的状态。 -
一个渲染通道是一个使用范围。如果子资源被任何(状态设置或非状态设置)指令引用,则该子资源在使用范围内“使用”。 例如,在
setBindGroup(index, bindGroup, dynamicOffsets)
中,bindGroup
中的每个子资源都在渲染通道的使用范围内“使用”。
上面说的应该是GPU 指令。 但是我们还没有办法引用特定的 GPU 指令(比如 dispatch)。
-
在渲染通道中,任何
setBindGroup()
调用中使用的子资源,无论是绑定的管道着色器或是实际上依赖于这些绑定的布局,还是被另一个“set”调用遮蔽的绑定组。 -
在任何
setVertexBuffer()
调用中使用的缓冲区,无论是否有任何绘制调用依赖于该缓冲区,或者该缓冲区是否被另一个“set”调用遮蔽。 -
在任何
setIndexBuffer()
调用中使用的缓冲区,无论是否有任何绘制调用依赖于该缓冲区,或者该缓冲区是否被另一个“set”调用遮蔽。 -
在 {GPURenderPassDescriptor}} 中被
beginRenderPass()
用作颜色附件、决议附件或深度/模板附件的纹理子资源,无论着色器是否实际上依赖于这些附件。 -
用于可见性为 0 的绑定组条目的资源,或仅对计算阶段可见但在渲染通道中使用的资源(反之亦然)。
在指令编码期间,子资源的每次使用都被记录在指令缓冲区的某一个使用范围中。对于每个使用范围,实现通过组合所有内部使用标识的列表来执行使用范围验证,这些内部使用标识的列表来自使用范围中的每个子资源。 如果这些列表中的任何一个不属于 兼容使用列表,则 GPUCommandEncoder.finish()
在当前错误范围内生成 GPUValidationError
。
3.5. 核心内部对象
3.5.1. 显卡适配器
显卡适配器标识系统上的 WebGPU 实现:浏览器底层平台上的计算/渲染功能实例,以及浏览器在该功能之上的 WebGPU 实现实例。
显卡适配器并不唯一的表示底层实现:多次调用 requestAdapter()
每次都会返回不同的适配器对象。
显卡适配器对象可能随时变为无效。这发生在“丢失设备”和“标记适配器过时”中。无效的显卡适配器无法创建新设备。
Note: 这种机制确保各种显卡适配器对场景的创建看起来与应用程序相似,因此更易以较少的测试保持更多场景的鲁棒性:首次初始化、由于未插入适配器而重新初始化、由于测试 GPUDevice.destroy()
调用而重新初始化等。这种机制还确保应用程序使用最新的系统状态,并以此来决定使用哪个适配器。
如果显卡适配器出现了显著的性能警告来换取更广泛的兼容性、更可预测的行为或更好的隐私性的某种组合,则可以将其视为应急适配器。 不需要在每个系统上都有可用的应急适配器。
显卡适配器具有以下内部插槽:
[[features]]
, of type ordered set<GPUFeatureName
>, readonly-
可以用作创建显卡适配器上设备的特性。
[[limits]]
, of type supported limits, readonly[[fallback]]
, of type boolean-
如果设为
true
, 则显卡适配器为应急适配器。
显卡适配器通过 GPUAdapter
暴露出来。
3.5.2. 设备
设备是显卡适配器的逻辑实例,内部对象通过设备被创建。设备可以在多个代理(例如专用 workers)之间共享。
设备是从其创建的所有内部对象的唯一所有者:当设备丢失或销毁
时,设备和在其上创建的所有对象变得隐式不可用,(直接对象,例如 createTexture()
,或间接对象,例如 {GPUTexture/createView()}})。
设备有以下内部插槽:
[[adapter]]
, of type adapter, readonly-
创建此设备的显卡适配器。
[[features]]
, of type ordered set<GPUFeatureName
>, readonly[[limits]]
, of type supported limits, readonly
GPUDeviceDescriptor
描述符从显卡适配器创建新设备时:
-
设置 device.
[[adapter]]
为 adapter. -
设置 device.
[[features]]
为 descriptor.requiredFeatures
中值的集。 -
让 device.
[[limits]]
成为具有默认值的可支持的限制对象。对于 descriptor.requiredLimits
中的每个(key, value) 对,将 device.[[limits]]
中 key 对应的成员设置为更好的值或可支持的限制中的默认值。
任何时候用户代理需要撤销对设备的访问,都会调用丢失设备(设备,undefined
)。
-
使 device.
[[adapter]]
无效。 -
使 device 无效。
-
解释如何从设备中获得它的“主”
GPUDevice
。 -
决议 device.
lost
返回一个新的GPUDeviceLostInfo
,reason
设置为 reason,并将message
设置成一个实现定义值。Note:
message
不应泄露不必要的用户/系统信息,也永远不应被应用程序解析。
3.6. 可选功能
WebGPU 显卡适配器和设备具有描述不同实现之间,不同的 WebGPU 功能的能力,不同的 WebGPU 功能通常是由于硬件或系统软件限制。能力要么是一个特性,要么是一个限制。
3.6.1. 特性
特性是一组可选的 WebGPU 功能,通常是由于硬件或系统软件限制,并非所有实现都支持。
每个 GPUAdapter
暴露一组可用特性。只有这些特性可能在 requestDevice()
中被请求。
仅当在设备创建时请求该特性,作为该特性一部分的功能才能被使用。 通过可选特性添加到现有词典中的词典成员在 WebIDL 级别始终是可选的; 如果未启用该特性,则不得将此类成员设置为非默认值。
Note: 虽然启用特性不会添加新的 IDL 必需字段,但可能不一定与现有代码向后兼容。 一个可选特性可以启用新的验证,使以前有效的代码无效。
有关每个特性启用的功能的描述,请参阅特性索引。
3.6.2. 限制
每个限制都是在设备上使用 WebGPU 的数字限制。
可支持的限制对象对每个定义的限制都有一个值。 每个显卡适配器都有一组受可支持的限制,并且创建
的设备具有特定的可支持的限制。 无论适配器的限制如何,都会强制执行设备限制。
每个限制都有一个默认值。每个显卡适配器都保证支持默认值或更好。如果是在 requiredLimits
)中未明确指定值,则使用默认值。
一个极限值可能比另一个更好。更好的限制值总是会放宽验证,从而使更多的程序有效。对于每个限制等级,都定义了“更好”。
不同的限制有不同的限制等级:
Note: 设置“更好”的限制不一定是可取的,因为它们可能会影响性能。因此,为了提高跨设备和实现的可移植性,应用程序通常应该请求适用于其内容的“最差”限制(理想情况下,默认值)。
限制名称 | 类型 | 限制等级 | 默认值 |
---|---|---|---|
maxTextureDimension1D
| GPUSize32
| 最大 | 8192 |
通过 dimension "1d" 创建的纹理,所允许的 size .width 的最大值。
| |||
maxTextureDimension2D
| GPUSize32
| 最大 | 8192 |
通过 dimension "2d" 创建的纹理,所允许的 size .width 和 size .height 的最大值。
| |||
maxTextureDimension3D
| GPUSize32
| 最大 | 2048 |
通过 dimension "3d" 创建的纹理,所允许的 size .width, size .height 和 size .depthOrArrayLayers 的最大值。
| |||
maxTextureArrayLayers
| GPUSize32
| 最大 | 256 |
通过 dimension "1d" 或 "2d" 创建的纹理,所允许的 size .depthOrArrayLayers 的最大值。
| |||
maxBindGroups
| GPUSize32
| 最大 | 4 |
创建 GPUPipelineLayout 时,bindGroupLayouts 中所允许的 GPUBindGroupLayouts 的最大值。
| |||
maxDynamicUniformBuffersPerPipelineLayout
| GPUSize32
| 最大 | 8 |
GPUPipelineLayout 中 GPUBindGroupLayoutEntry 输入接口的最大数量,这些输入接口是具有动态偏移的统一缓冲区。 详见超出绑定槽限制。
| |||
maxDynamicStorageBuffersPerPipelineLayout
| GPUSize32
| 最大 | 4 |
GPUPipelineLayout 中 GPUBindGroupLayoutEntry 条目的最大数量,这些条目是具有动态偏移的存储缓冲区。 详见超出绑定槽限制。
| |||
maxSampledTexturesPerShaderStage
| GPUSize32
| 最大 | 16 |
对每个可能的 GPUShaderStage 阶段 ,GPUPipelineLayout 中作为采样纹理的 GPUBindGroupLayoutEntry 条目的最大数量。详见超出绑定槽限制。
| |||
maxSamplersPerShaderStage
| GPUSize32
| 最大 | 16 |
对每个可能的 GPUShaderStage 阶段 ,GPUPipelineLayout 中作为采样器的 GPUBindGroupLayoutEntry 条目的最大数量。详见超出绑定槽限制。
| |||
maxStorageBuffersPerShaderStage
| GPUSize32
| 最大 | 8 |
对每个可能的 GPUShaderStage 阶段 ,GPUPipelineLayout 中作为存储缓冲区的 GPUBindGroupLayoutEntry 条目的最大数量。详见超出绑定槽限制。
| |||
maxStorageTexturesPerShaderStage
| GPUSize32
| 最大 | 4 |
对每个可能的 GPUShaderStage 阶段 ,GPUPipelineLayout 中作为存储纹理的 GPUBindGroupLayoutEntry 条目的最大数量。详见超出绑定槽限制。
| |||
maxUniformBuffersPerShaderStage
| GPUSize32
| 最大 | 12 |
对每个可能的 GPUShaderStage 阶段 ,GPUPipelineLayout 中作为统一缓冲区的 GPUBindGroupLayoutEntry 条目的最大数量。详见超出绑定槽限制。
| |||
maxUniformBufferBindingSize
| GPUSize32
| 最大 | 16384 |
用 GPUBindGroupLayoutEntry 条目做绑定的最大 GPUBufferBinding .size ,这个条目 entry.buffer ?.type 为 "uniform" 。
| |||
maxStorageBufferBindingSize
| GPUSize32
| 最大 | 134217728 (128 MiB) |
用 GPUBindGroupLayoutEntry 条目做绑定的最大 GPUBufferBinding .size ,这个条目 entry.buffer ?.type 为 "storage" 或 "read-only-storage" 。
| |||
minUniformBufferOffsetAlignment
| GPUSize32
| 对齐 | 256 |
用 GPUBindGroupLayoutEntry 条目做绑定时,GPUBufferBinding .offset 和 setBindGroup dynamicOffsets 参数所需的对齐方式,这个条目 entry.buffer ?.type 为 "uniform" 。
| |||
minStorageBufferOffsetAlignment
| GPUSize32
| 对齐 | 256 |
用 GPUBindGroupLayoutEntry 条目做绑定时,GPUBufferBinding .offset 和 setBindGroup dynamicOffsets 参数所需的对齐方式,这个条目 entry.buffer ?.type 为 "storage" 或 "read-only-storage" 。
| |||
maxVertexBuffers
| GPUSize32
| 最大 | 8 |
创建 GPURenderPipeline 时 buffers 的最大值。
| |||
maxVertexAttributes
| GPUSize32
| 最大 | 16 |
创建 GPURenderPipeline 时在所有 buffers 中 attributes 的最大值。
| |||
maxVertexBufferArrayStride
| GPUSize32
| 最大 | 2048 |
创建 GPURenderPipeline 时 arrayStride 所允许的的最大值。
| |||
maxInterStageShaderComponents
| GPUSize32
| 最大 | 60 |
用于内部阶段间通信的输入或输出变量的最大允许组件数(如顶点输出或片段输入)。 | |||
maxComputeWorkgroupStorageSize
| GPUSize32
| 最大 | 16352 |
用于计算阶段 GPUShaderModule 入口点的最大字节数。
| |||
maxComputeInvocationsPerWorkgroup
| GPUSize32
| 最大 | 256 |
计算阶段 GPUShaderModule 入口点的 workgroup_size 维度乘积的最大值。
| |||
maxComputeWorkgroupSizeX
| GPUSize32
| 最大 | 256 |
计算阶段 GPUShaderModule 入口点的 workgroup_size X 维度的最大值。
| |||
maxComputeWorkgroupSizeY
| GPUSize32
| 最大 | 256 |
计算阶段 GPUShaderModule 入口点的 workgroup_size Y 维度的最大值。
| |||
maxComputeWorkgroupSizeZ
| GPUSize32
| 最大 | 64 |
计算阶段 GPUShaderModule 入口点的 workgroup_size Z 维度的最大值。
| |||
maxComputeWorkgroupsPerDimension
| GPUSize32
| 最大 | 65535 |
dispatch(x, y, z) 参数的最大值。
|
3.6.2.1. GPUSupportedLimits
GPUSupportedLimits
暴露一个显卡适配器或设备支持的限制。详见 GPUAdapter.limits
和 GPUDevice.limits
.
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUSupportedLimits {readonly attribute unsigned long ;
maxTextureDimension1D readonly attribute unsigned long ;
maxTextureDimension2D readonly attribute unsigned long ;
maxTextureDimension3D readonly attribute unsigned long ;
maxTextureArrayLayers readonly attribute unsigned long ;
maxBindGroups readonly attribute unsigned long ;
maxDynamicUniformBuffersPerPipelineLayout readonly attribute unsigned long ;
maxDynamicStorageBuffersPerPipelineLayout readonly attribute unsigned long ;
maxSampledTexturesPerShaderStage readonly attribute unsigned long ;
maxSamplersPerShaderStage readonly attribute unsigned long ;
maxStorageBuffersPerShaderStage readonly attribute unsigned long ;
maxStorageTexturesPerShaderStage readonly attribute unsigned long ;
maxUniformBuffersPerShaderStage readonly attribute unsigned long long ;
maxUniformBufferBindingSize readonly attribute unsigned long long ;
maxStorageBufferBindingSize readonly attribute unsigned long ;
minUniformBufferOffsetAlignment readonly attribute unsigned long ;
minStorageBufferOffsetAlignment readonly attribute unsigned long ;
maxVertexBuffers readonly attribute unsigned long ;
maxVertexAttributes readonly attribute unsigned long ;
maxVertexBufferArrayStride readonly attribute unsigned long ;
maxInterStageShaderComponents readonly attribute unsigned long ;
maxComputeWorkgroupStorageSize readonly attribute unsigned long ;
maxComputeInvocationsPerWorkgroup readonly attribute unsigned long ;
maxComputeWorkgroupSizeX readonly attribute unsigned long ;
maxComputeWorkgroupSizeY readonly attribute unsigned long ;
maxComputeWorkgroupSizeZ readonly attribute unsigned long ; };
maxComputeWorkgroupsPerDimension
3.6.2.2. GPUSupportedFeatures
GPUSupportedFeatures
是一个setlike 接口。这个接口的set entries是一个显卡适配器或设备支持的特性的 {GPUFeatureName}} 值。这个接口必须只包含 GPUFeatureName
枚举中的字符串。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUSupportedFeatures {readonly setlike <DOMString >; };
GPUSupportedFeatures
的set entries的类型是 DOMString
,以允许用户代理优雅地处理有效的 GPUFeatureName
s,这些GPUFeatureName
s在规范的后续版本中添加,但用户代理尚未更新以识别。如果设置的条目类型是 GPUFeatureName
,以下代码将产生TypeError
而不是报告 false
:
3.7. 源限制
WebGPU 允许访问存储在图像、视频和画布中的图像数据。跨域媒体的使用受到限制,因为着色器可用于间接推断已上传到 GPU 的纹理内容。
如果图像源is not origin-clean,则 WebGPU 不允许上传图像源。
这也意味着使用 WebGPU 渲染的画布的origin-clean标识永远不会设置为 false
。
有关为图像和视频元素发出 CORS 请求的更多信息,请参阅:
3.8. 颜色空间和编码
WebGPU 不提供颜色管理。 WebGPU 中的所有值(例如纹理元素)都是原始数值,而不是颜色管理的颜色值。
WebGPU 有颜色管理的输出(通过 GPUCanvasConfiguration
)和输入(通过 copyExternalImageToTexture()
和 {GPUDevice/importExternalTexture()}})接口。因此,必须在 WebGPU 数值和外部颜色值之间进行颜色转换。每个这样的接口点在本地定义一个编码(颜色空间、传递函数和alpha预乘),通过这个编码过程对 WebGPU 数值进行解析。
如果由引用的 CSS 定义,来表示其空间之外的颜色值(色度和亮度),则每个颜色空间都在扩展范围内定义。
enum {
GPUPredefinedColorSpace "srgb" , };
可能用 PredefinedColorSpace 来替换,但请注意,这样做意味着当项目被添加到上游规范中的枚举时,新的 WebGPU 功能会自动添加。
考虑将srgb编码图像上传到线性编码纹理的路径。 [Issue #gpuweb/gpuweb#1715]
"srgb"
-
CSS预定义颜色空间srgb。
3.8.1. 色彩空间转换
根据上述定义,通过将颜色在一个空间中的表示转换为另一个空间中的表示,可以在空间之间转换颜色。
如果源值少于4个通道,则剩余的绿色/蓝色/Alpha 通道在转换颜色空间/编码和 alpha 预乘之前,根据需要分别为设置为 0, 0, 1
。转换后,如果目的地需要少于4个通道,则多余的通道会被忽略。
颜色在转换过程中不会有损地强制执行:如果源颜色值超出目标色彩空间的色域范围(例如,如果将显示P3图像转换为sRGB),从一个色彩空间至另一个色彩空间的颜色转换会导致值超出范围[0, 1]。
4. 初始化
4.1. navigator.gpu
GPU
对象分别通过 Navigator
和 WorkerNavigator
接口在 Window
和 DedicatedWorkerGlobalScope
上下文中可用,
并通过 navigator.gpu
被暴露:
interface mixin { [
NavigatorGPU SameObject ,SecureContext ]readonly attribute GPU ; };
gpu Navigator includes NavigatorGPU ;WorkerNavigator includes NavigatorGPU ;
4.2. GPU
GPU
是进入 WebGPU 的入口。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPU {Promise <GPUAdapter ?>requestAdapter (optional GPURequestAdapterOptions options = {}); };
GPU
的获取有如下方法:
requestAdapter(options)
-
从用户代理请求 显卡适配器。 用户代理选择是否返回适配器,如果返回, 根据提供的选项进行选择。
调用:GPU
this.参数:
Arguments for the GPU.requestAdapter(options) method. Parameter Type Nullable Optional Description options
GPURequestAdapterOptions
✘ ✔ 用来选择显卡适配器的标准 返回:
Promise
<GPUAdapter
?>-
让 promise 成为一个 a new promise.
-
在 this 设备时间线上执行以下步骤 :
-
如果用户代理选择返回一个适配器,用户代理应该:
-
创建一个有效的显卡适配器 adapter,根据§ 4.2.1 适配器选择规则和 options 标准进行选择。
-
如果 adapter 满足应急适配器的标准,设定 adapter.
[[fallback]]
为true
. -
使用新的
GPUAdapter
封装 adapter,来决议 promise.
-
-
否则, promise 决议为
null
.
-
-
返回 promise.
-
GPU
有以下内部插槽:
[[previously_returned_adapters]]
, of type ordered set<adapter>-
通过
requestAdapter()
返回的显卡适配器集。 在标记适配器过时中,显卡适配器被使用,然后被清除。
当系统状态发生任何变化,并可能影响任何 requestAdapter()
的调用结果时,用户代理应该标记适配器过时。 例如:
-
添加/移除物理适配器(通过插头、驱动程序更新、TDR 等)
-
系统的电源配置已更改(笔记本电脑已拔下电源,电源设置已更改等)
此外,标记适配器过时可以随时被调用。即使没有系统状态改变,用户代理也可以经常选择调用(例如,最后一次调用 requestDevice()
后几秒)。这对格式良好的应用程序没有影响,模糊了真实的系统状态变化,并使
开发人员更清楚的了解了,在调用 requestDevice()
之前,总是需要再次调用 requestAdapter()
。
-
对于在
navigator.gpu.
[[previously_returned_adapters]]
中的每一个adapter:-
使adapter.
[[adapter]]
无效。
-
-
清空
navigator.gpu.
[[previously_returned_adapters]]
.
4.2.1. 适配器选择
GPURequestAdapterOptions
向用户代理提供提示,指示了适合应用程序的配置。
dictionary GPURequestAdapterOptions {GPUPowerPreference powerPreference ;boolean forceFallbackAdapter =false ; };
enum {
GPUPowerPreference "low-power" ,"high-performance" , };
GPURequestAdapterOptions
有以下选择:
powerPreference
, of type GPUPowerPreference-
可选的提供一个提示,指示应从系统的可用适配器中选择什么类的显卡适配器。
这个提示的值可能会影响选择哪个适配器,但不能影响是否返回适配器。
Note: 此提示的主要用途是影响多 GPU 系统中使用的 GPU。例如,一些笔记本电脑有一个低功耗的集成 GPU 和一个高性能的独立 GPU。
Note: 根据确切的硬件配置,例如电池状态和连接的显示器或可移动 GPU,用户代理可能会选择不同的显卡适配器给定相同的电源首选项。通常,给定相同的硬件配置和状态以及 “powerPreference”,用户代理可能会选择相同的适配器。
必须是以下值之一:
undefined
(or not present)-
不提供任何提示给用户代理.
"low-power"
-
指示一个将节能优先于性能的请求。
Note: 通常,如果不太可能受到绘图性能的限制,则内容应使用这种配置; 例如,如果它每秒只渲染一帧,使用简单的着色器只绘制相对简单的几何图形,或者使用小的 HTML 画布元素。如果内容允许,鼓励开发人员使用此值,因为它可以显著提高便携式设备的电池寿命。
"high-performance"
-
指示一个将性能优先于功耗的请求。
Note: 通过选择这个值,开发人员应该了解,对于在生成的适配器上创建的设备,用户代理更有可能强制设备丢失,以便通过切换到低功率适配器来节省功率。仅在绝对必要时鼓励开发人员指定此值,因为这种设置可能会显着缩短便携式设备的电池寿命。
forceFallbackAdapter
, of type boolean, defaulting tofalse
-
当设置为
true
时表示只能返回应急适配器。 如果用户代理不支持应急适配器,会导致requestAdapter()
返回null
。Note: 如果
forceFallbackAdapter
被设置为false
,并且没有其他合适的 显卡适配器可用或用户代理选择返回一个应急适配器,requestAdapter()
仍可能返回应急适配器。希望阻止其应用程序在应急适配器上运行的开发人员,应在请求GPUDevice
之前检查GPUAdapter
.isFallbackAdapter
属性。
4.3. GPUAdapter
一个 GPUAdapter
封装了一个显卡适配器,并描述其能力(特性和限制)。
使用 requestAdapter()
来获取 GPUAdapter
。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUAdapter {readonly attribute DOMString name ; [SameObject ]readonly attribute GPUSupportedFeatures features ; [SameObject ]readonly attribute GPUSupportedLimits limits ;readonly attribute boolean isFallbackAdapter ;Promise <GPUDevice >requestDevice (optional GPUDeviceDescriptor descriptor = {}); };
GPUAdapter
有以下属性:
name
, of type DOMString, readonly-
标识适配器的可读名称。 内容是实现定义的。
features
, of type GPUSupportedFeatures, readonly-
this
.[[adapter]]
.[[features]]
中值的集合。 limits
, of type GPUSupportedLimits, readonly-
this
.[[adapter]]
.[[limits]]
中的限值。 isFallbackAdapter
, of type boolean, readonly-
返回
[[adapter]]
.[[fallback]]
的值。
GPUAdapter
有以下内部插槽:
[[adapter]]
, of type adapter, readonly-
此
GPUAdapter
所指的显卡适配器。
GPUAdapter
有以下方法:
requestDevice(descriptor)
-
调用:
GPUAdapter
this.参数:
Arguments for the GPUAdapter.requestDevice(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUDeviceDescriptor
✘ ✔ 要请求的 GPUDevice
的描述。-
让 promise 成为一个 a new promise.
-
让 adapter 作为 this.
[[adapter]]
. -
在设备时间线上执行以下步骤:
-
如果以下任意条件没有满足,通过生成
TypeError
reject promise,然后停止运行。-
descriptor.
requiredFeatures
中的值的集合,必须是 adapter.[[features]]
中值的子集.
Note: 如果是浏览器根本不知道的特性名称(在其
GPUFeatureName
定义中),则会产生相同的错误。这将浏览器不支持某个特性时的行为与特定适配器不支持某个特性时的行为融合在一起。 -
-
如果以下任意条件没有满足,通过生成
OperationError
reject promise,然后停止运行。-
descriptor.
requiredLimits
中的每一个key,必须是支持的限制中的成员的一个. -
对于支持的限制中的每个keys中的限制名称 key:使 value 为 descriptor.
requiredLimits
[key].-
value 必须不比 adapter.
[[limits]]
中的限制值更好。
-
-
-
如果 adapter 为无效,或者用户代理无法满足请求:
-
-
返回 promise.
-
GPUDevice
:
const gpuAdapter= await navigator. gpu. requestAdapter(); const gpuDevice= await gpuAdapter. requestDevice();
4.3.1. GPUDeviceDescriptor
GPUDeviceDescriptor
描述一个设备请求。
dictionary GPUDeviceDescriptor :GPUObjectDescriptorBase {sequence <GPUFeatureName >requiredFeatures = [];record <DOMString ,GPUSize64 >requiredLimits = {}; };
GPUDeviceDescriptor
有以下成员:
requiredFeatures
, of type sequence<GPUFeatureName>, defaulting to[]
-
指定设备请求所需的特性。如果适配器无法提供这些特性,则请求将失败。
由生成的设备上的 API 调用验证时,将允许不多不少完全指定的一组特性。
requiredLimits
, of type record<DOMString, GPUSize64>, defaulting to{}
-
指定设备请求所需的限制。如果适配器无法提供这些限制,则请求将失败。
"texture-compression-astc"
特性的 GPUDevice
:
const gpuAdapter= await navigator. gpu. requestAdapter(); const requiredFeatures= []; if ( gpuAdapter. features. has( 'texture-compression-astc' )) { requiredFeatures. push( 'texture-compression-astc' ) } const gpuDevice= await gpuAdapter. requestDevice({ requiredFeatures});
4.3.1.1. GPUFeatureName
每个 GPUFeatureName
标识一组功能,这组功能如果可用,则允许额外使用 WebGPU,否则这些 WebGPU 的额外使用被视为无效。
enum GPUFeatureName {"depth-clip-control" ,"depth24unorm-stencil8" ,"depth32float-stencil8" ,"texture-compression-bc" ,"texture-compression-etc2" ,"texture-compression-astc" ,"timestamp-query" ,"indirect-first-instance" , };
4.4. GPUDevice
一个 GPUDevice
封装了一个设备,并暴露了该设备的功能。
GPUDevice
用来创建 WebGPU 接口的顶层接口。
使用 requestDevice()
,来获得 GPUDevice
。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUDevice :EventTarget { [SameObject ]readonly attribute GPUSupportedFeatures features ; [SameObject ]readonly attribute GPUSupportedLimits limits ; [SameObject ]readonly attribute GPUQueue queue ;undefined destroy ();GPUBuffer createBuffer (GPUBufferDescriptor descriptor );GPUTexture createTexture (GPUTextureDescriptor descriptor );GPUSampler createSampler (optional GPUSamplerDescriptor descriptor = {});GPUExternalTexture importExternalTexture (GPUExternalTextureDescriptor descriptor );GPUBindGroupLayout createBindGroupLayout (GPUBindGroupLayoutDescriptor descriptor );GPUPipelineLayout createPipelineLayout (GPUPipelineLayoutDescriptor descriptor );GPUBindGroup createBindGroup (GPUBindGroupDescriptor descriptor );GPUShaderModule createShaderModule (GPUShaderModuleDescriptor descriptor );GPUComputePipeline createComputePipeline (GPUComputePipelineDescriptor descriptor );GPURenderPipeline createRenderPipeline (GPURenderPipelineDescriptor descriptor );Promise <GPUComputePipeline >createComputePipelineAsync (GPUComputePipelineDescriptor descriptor );Promise <GPURenderPipeline >createRenderPipelineAsync (GPURenderPipelineDescriptor descriptor );GPUCommandEncoder createCommandEncoder (optional GPUCommandEncoderDescriptor descriptor = {});GPURenderBundleEncoder createRenderBundleEncoder (GPURenderBundleEncoderDescriptor descriptor );GPUQuerySet createQuerySet (GPUQuerySetDescriptor descriptor ); };GPUDevice includes GPUObjectBase ;
GPUDevice
有以下属性:
features
, of type GPUSupportedFeatures, readonly-
包含设备支持的特性(即创建时具有的特性)的
GPUFeatureName
值的集合。 limits
, of type GPUSupportedLimits, readonly-
暴露设备支持的限制(同时也是创建时具有的限制)。
queue
, of type GPUQueue, readonly-
此设备的主要
GPUQueue
。
GPUDevice
的 [[device]]
是 GPUDevice
引用的设备。
GPUDevice
具有上面的 WebIDL 定义中列出的方法。此处未定义的内容在本文档的其他地方进行了定义。
destroy()
-
销毁设备,防止对其进行进一步操作。未完成的异步操作将失败。
调用:GPUDevice
this.-
丢失设备(this.
[[device]]
,"destroyed"
).
Note: 由于此设备上不能发生进一步的操作,因此实现可以释放资源分配,并立即中止未完成的异步操作。
-
GPUDevice
对象是 serializable objects。
完成定义多线程 API,并将“[Serializable]”添加回接口。 [Issue #gpuweb/gpuweb#354]
-
设置 serialized.agentCluster 为surrounding agent 的代理集群。
-
如果 serialized.agentCluster 的cross-origin isolated capability 为 false,则返回 “
DataCloneError
”。 -
如果 forStorage 是
true
,返回 “DataCloneError
”。 -
将 serialized.device 设置为 value.
[[device]]
的值。
-
如果 serialized.agentCluster 不是surrounding agent 的代理集群,则返回 “
DataCloneError
”。 -
将 value.
[[device]]
设置为 serialized.device。
GPUDevice
并不真正需要跨域策略限制。无论如何,应该可以从多个代理使用。一旦我们描述了缓冲区、纹理和队列的序列化 - COOP+COEP 逻辑应该被移到那里。
4.5. 示例
GPUAdapter
和 GPUDevice
的示例,该示例还包含了错误处理:
let gpuDevice= null ; async function initializeWebGPU() { // Check to ensure the user agent supports WebGPU. if ( ! ( 'gpu' in navigator)) { console. error( 'User agent doesn’t support WebGPU.' ); return false ; } // Request an adapter. const gpuAdapter= await navigator. gpu. requestAdapter(); // requestAdapter may resolve with null if no suitable adapters are found. if ( ! gpuAdapter) { console. error( 'No WebGPU adapters found.' ); return false ; } // Request a device. // Note that the promise will reject if invalid options are passed to the optional // dictionary. To avoid the promise rejecting always check any features and limits // against the adapters features and limits prior to calling requestDevice(). gpuDevice= await gpuAdapter. requestDevice(); // requestDevice will never return null, but if a valid device request can’t be // fulfilled for some reason it may resolve to a device which has already been lost. // Additionally, devices can be lost at any time after creation for a variety of reasons // (ie: browser resource management, driver updates), so it’s a good idea to always // handle lost devices gracefully. gpuDevice. lost. then(( info) => { console. error( `WebGPU device was lost: ${ info. message} ` ); gpuDevice= null ; // Many causes for lost devices are transient, so applications should try getting a // new device once a previous one has been lost unless the loss was caused by the // application intentionally destroying the device. Note that any WebGPU resources // created with the previous device (buffers, textures, etc) will need to be // re-created with the new one. if ( info. reason!= 'destroyed' ) { initializeWebGPU(); } }); onWebGPUInitialized(); return true ; } function onWebGPUInitialized() { // Begin creating WebGPU resources here... } initializeWebGPU();
5. 缓冲区
5.1. GPUBuffer
GPUBuffer
表示可用于 GPU 操作的内存块。数据以线性布局存储,这意味着分配的每个字节都可以由其从 GPUBuffer
开始的偏移量寻址,并且受到操作的对齐约束限制。一些 GPUBuffers
可以被映射,这使得内存块可以通过一个ArrayBuffer
访问并调用它的映射。
GPUBuffers
是通过 GPUDevice.createBuffer(descriptor)
创建的,
创建后会返回一个处于 已映射 或 未映射状态的新缓冲区。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUBuffer {Promise <undefined >mapAsync (GPUMapModeFlags mode ,optional GPUSize64 offset = 0,optional GPUSize64 size );ArrayBuffer getMappedRange (optional GPUSize64 offset = 0,optional GPUSize64 size );undefined unmap ();undefined destroy (); };GPUBuffer includes GPUObjectBase ;
GPUBuffer
有如下内部插槽:
[[size]]
of typeGPUSize64
.-
GPUBuffer
被分配的长度(以字节为单位)。 [[usage]]
of typeGPUBufferUsageFlags
.-
此
GPUBuffer
被允许的使用。 [[state]]
of type buffer state.-
GPUBuffer
的当前状态。 [[mapping]]
of typeArrayBuffer
orPromise
ornull
.-
此
GPUBuffer
的映射。ArrayBuffer
不能直接被访问,而是通过视图去访问,称为映射范围,被存储在[[mapped_ranges]]
中。在
DataBlock
方面指定[[mapping]]
类似于AllocateArrayBuffer
? [Issue #gpuweb/gpuweb#605] [[mapping_range]]
of type list<unsigned long long
> ornull
.-
此被映射的
GPUBuffer
的范围。 [[mapped_ranges]]
of type list<ArrayBuffer
> ornull
.-
ArrayBuffer
s 通过getMappedRange
返回给应用程序。这些ArrayBuffer
s 会被追踪,以便在unmap
被调用时可以将其分离。 [[map_mode]]
of typeGPUMapModeFlags
.-
最后一次调用
mapAsync()
的GPUMapModeFlags
(如果有)。
[[usage]]
与 [[descriptor]]
.usage
的命名不同。我们应该让两种命名保持一致。
每个 GPUBuffer
在内容时间线上都有一个当前的缓冲区状态,它是以下几项之一:
-
"已映射" 此时
GPUBuffer
中的内容可以被用作 CPU 操作。 -
"在创建时被映射" 此时
GPUBuffer
刚刚被创建,并且其中的内容可以被 CPU 操作。 -
"待映射" 此时
GPUBuffer
正在被处理使得它的内容可以被 CPU 操作。 -
"未映射" 此时
GPUBuffer
允许 GPU 操作。
Note: 一旦创建了 GPUBuffer
,[[size]]
和 [[usage]]
是不可变的。
GPUBuffer
有一个具有以下状态的状态机。(([[mapping]]
, [[mapping_range]]
, 并且 [[mapped_ranges]]
在未指定时为空。)
-
已映射或在创建时被映射状态,同时包含一个类型为
[[mapping]]
的ArrayBuffer
,一个[[mapping_range]]
中两个数字的序列,和一个[[mapped_ranges]]
中ArrayBuffer
的序列。 -
待映射状态,同时包含一个类型为
[[mapping]]
的Promise
。
GPUBuffer
是对一个内部缓冲区对象的引用。
完成定义多线程 API 并将 [Serializable]
添加回接口。 [Issue #gpuweb/gpuweb#354]
5.2. 缓冲区创建
5.2.1. GPUBufferDescriptor
指定了创建 GPUBuffer
用到的选项。
dictionary :
GPUBufferDescriptor GPUObjectDescriptorBase {required GPUSize64 ;
size required GPUBufferUsageFlags ;
usage boolean =
mappedAtCreation false ; };
-
mappedAtCreation
保证即使缓冲区最终创建失败,缓冲区仍然看起来好像可以在映射的范围内写入/读取,直到缓冲区回到未映射状态。
5.2.2. 缓冲区使用
typedef [EnforceRange ]unsigned long ; [
GPUBufferUsageFlags Exposed =(Window ,DedicatedWorker )]namespace {
GPUBufferUsage const GPUFlagsConstant = 0x0001;
MAP_READ const GPUFlagsConstant = 0x0002;
MAP_WRITE const GPUFlagsConstant = 0x0004;
COPY_SRC const GPUFlagsConstant = 0x0008;
COPY_DST const GPUFlagsConstant = 0x0010;
INDEX const GPUFlagsConstant = 0x0020;
VERTEX const GPUFlagsConstant = 0x0040;
UNIFORM const GPUFlagsConstant = 0x0080;
STORAGE const GPUFlagsConstant = 0x0100;
INDIRECT const GPUFlagsConstant = 0x0200; };
QUERY_RESOLVE
createBuffer(descriptor)
-
创建一个
GPUBuffer
。调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createBuffer(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUBufferDescriptor
✘ ✘ 要创建的 GPUBuffer
的描述。返回:
GPUBuffer
-
如果以下任何条件没有满足,返回一个错误缓冲区并停止。
-
descriptor.
usage
必须不为 0。 -
descriptor.
usage
是 this.[[allowed buffer usages]] 的一个子集。 -
如果 descriptor.
mappedAtCreation
为true
:-
descriptor.
size
是 4 的倍数。
-
解释什么是
GPUDevice
的[[allowed buffer usages]]
. [Issue #gpuweb/gpuweb#605]
Note: 如果缓冲区创建失败,并且 descriptor.
mappedAtCreation
为false
,对mapAsync()
的任何调用都将被拒绝,因此开始映射中分配的任何资源都可以并且可能会被丢弃或回收。-
使 b 为一个新的
GPUBuffer
对象. -
如果 descriptor.
mappedAtCreation
值为true
:-
将 b.
[[mapping]]
设置为一个新的大小为 b.[[size]]
的ArrayBuffer
。 -
将 b.
[[mapping_range]]
设置为[0, descriptor.size]
. -
将 b.
[[mapped_ranges]]
设置为[]
.
否则:
-
将 b.
[[mapping]]
设置为null
。 -
将 b.
[[mapping_range]]
设置为null
。 -
将 b.
[[mapped_ranges]]
设置为null
。
-
-
将 b 分配的每个字节设置为零。
-
返回 b.
Note: 在
usage
中没有MAP_READ
或MAP_WRITE
的情况下,将mappedAtCreation
设置为true
是有效的。这可用于设置缓冲区的初始数据。 -
const buffer= gpuDevice. createBuffer({ size: 128 , usage: GPUBufferUsage. UNIFORM| GPUBufferUsage. COPY_DST});
5.3. 缓冲区销毁
不再需要 GPUBuffer
的应用程序可以选择通过调用 {{GPUBuffer/destroy()},在垃圾回收之前,丢弃对缓冲区的访问。销毁缓冲区的同时,也使缓冲区回到未映射状态,释放为映射分配的任何内存。
Note: 一旦先前提交的所有使用 GPUBuffer
的操作完成,用户代理可以回收与 GPUBuffer
关联的 GPU 内存。
destroy()
-
销毁
GPUBuffer
.
5.4. 缓冲区映射
应用程序可以请求映射 GPUBuffer
,使得这些应用程序可以通过 ArrayBuffers 访问其内容,这些 ArrayBuffers 代表了 GPUBuffer
的部分分配。使用 mapAsync()
异步请求映射 GPUBuffer
,使得户代理可以确保 GPU 在应用程序可以访问其内容之前完成对 GPUBuffer
的使用。一旦 GPUBuffer
被映射,应用程序就可以使用 getMappedRange
同步请求访问其内容范围。已映射的 GPUBuffer
不能被 GPU 使用,并且必须在被使用到的工作任务提交到队列时间线之前,使用 unmap
使其回到未映射状态。
添加客户端校验,使已映射缓冲区只能在其映射的 worker 上取消映射和销毁。同样 getMappedRange
只能在该 worker 上被调用。 [Issue #gpuweb/gpuweb#605]
typedef [EnforceRange ]unsigned long ; [
GPUMapModeFlags Exposed =(Window ,DedicatedWorker )]namespace {
GPUMapMode const GPUFlagsConstant = 0x0001;
READ const GPUFlagsConstant = 0x0002; };
WRITE
mapAsync(mode, offset, size)
-
映射
GPUBuffer
的给定范围,并在GPUBuffer
的内容准备好可以使用getMappedRange()
访问时,决议返回的 Promise。调用:GPUBuffer
this.参数:
Arguments for the GPUBuffer.mapAsync(mode, offset, size) method. Parameter Type Nullable Optional Description mode
GPUMapModeFlags
✘ ✘ 缓冲区是否应当被映射为读取或写入。 offset
GPUSize64
✘ ✔ 以字节为单位的缓冲区到要映射的范围起始位置的偏移量。 size
GPUSize64
✘ ✔ 以字节为单位的要映射的范围大小。 一旦我们有了错误单子的描述,即刻处理错误缓冲区。 [Issue #gpuweb/gpuweb#605]
-
如果 size 字段丢失:
-
使 rangeSize 为 max(0, this.
[[size]]
- offset)。
否则, 使 rangeSize 为 size。
-
-
如果以下任何条件未被满足:
接下来:
-
记录当前范围内的校验错误。
-
-
使 p 为一个新的
Promise
。 -
设置 this.
[[mapping]]
为 p。 -
设置 this.
[[map_mode]]
为 mode。 -
在默认队列上的队列时间线对操作进行入队操作,该行为将执行以下操作:
-
-
使 m 为一个新的大小为 rangeSize 的
ArrayBuffer
。 -
将 m 的内容设置为 this 分配的内容,从偏移 offset 开始分配,且分配 rangeSize 字节。
-
将 this.
[[mapping]]
设置为 m. -
将 this.
[[mapping_range]]
设置为[offset, offset + rangeSize]
. -
将 this.
[[mapped_ranges]]
设置为[]
.
-
-
Resolve p.
-
-
返回 p。
-
getMappedRange(offset, size)
-
返回一个带有给定范围内
GPUBuffer
内容的ArrayBuffer
。调用:GPUBuffer
this.参数:
Arguments for the GPUBuffer.getMappedRange(offset, size) method. Parameter Type Nullable Optional Description offset
GPUSize64
✘ ✔ 以字节为单位的缓冲区偏移量,返回缓冲区内容的位置。 size
GPUSize64
✘ ✔ 以字节为单位的,要返回的 ArrayBuffer
大小。返回:
ArrayBuffer
-
如果 size 缺失:
-
使 rangeSize 为 max(0, this.
[[size]]
- offset)。
否则, 使 rangeSize 为 size。
-
-
如果任何以下条件未满足, 产生一个
OperationError
异常并停止。-
offset 是 8 的倍数。
-
rangeSize 是 4 的倍数。
-
offset 等于或大于 this.
[[mapping_range]]
[0]。 -
offset + rangeSize 小于或等于 this.
[[mapping_range]]
[1]. -
[offset, offset + rangeSize) 不与另一个 this.
[[mapped_ranges]]
范围重叠。
Note: 获取在创建时被映射的
GPUBuffer
的映射范围总是有效的,即使它是无效的,因为内容时间线可能不知道它是无效的。 -
使 m 为一个新的大小为 rangeSize 的
ArrayBuffer
,指向 this.[[mapping]]
的内容偏移量 offset - this.[[mapping_range]]
[0]。 -
添加 (Append) m 至 this.
[[mapped_ranges]]
。 -
返回m。
-
unmap()
-
对已映射的
GPUBuffer
范围取消映射,并且使得其内容可以重新被 GPU 使用。调用:GPUBuffer
this.返回:
undefined
-
如果以下任何需求没有满足,产生一个校验错误并停止。
-
-
拒绝
[[mapping]]
,产生一个AbortError
。 -
设置 this.
[[mapping]]
为null
。
-
-
如果 this.
[[state]]
为已映射或在创建时被映射:-
如果以下两条件之一成立:
则接下来:
-
在默认队列的队列时间线上将操作入队,该操作将 this.
[[mapping_range]]
的 this 分配更新为 this.[[mapping]]
的内容。
-
-
将 this.
[[mapped_ranges]]
中的每个ArrayBuffer
与其内容分离。 -
将 this.
[[mapping]]
设置为null
. -
将 this.
[[mapping_range]]
设置为null
. -
将 this.
[[mapped_ranges]]
设置为null
.
-
Note: 当
MAP_READ
缓冲区(目前未在创建时被映射)被取消映射时,应用程序对映射范围ArrayBuffer
所做的任何本地修改都将被丢弃,并且不会影响后续映射的内容。 -
6. 纹理和纹理视图
定义 mipmap level, array layer, aspect, slice(概念)
6.1. GPUTexture
GPUTextures
是通过创建 GPUDevice.createTexture(descriptor)
返回的一个新的纹理。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUTexture {GPUTextureView createView (optional GPUTextureViewDescriptor descriptor = {});undefined destroy (); };GPUTexture includes GPUObjectBase ;
GPUTexture
有以下内部插槽:
[[descriptor]]
,GPUTextureDescriptor
类型-
GPUTextureDescriptor
描述这个纹理.GPUTextureDescriptor
的所有可选字段都已定义。 [[destroyed]]
,boolean
类型, 初始设定为 false-
如果纹理被破坏,该纹理就不能再用于任何操作,并且其底层内存可以被释放。
参数:
-
GPUExtent3D
baseSize -
GPUSize32
mipLevel
返回: GPUExtent3DDict
-
让 extent 成为一个新的
GPUExtent3DDict
对象。 -
设置 extent.
depthOrArrayLayers
为 1. -
返回 extent.
6.1.1. 纹理创建
dictionary :
GPUTextureDescriptor GPUObjectDescriptorBase {required GPUExtent3D ;
size GPUIntegerCoordinate = 1;
mipLevelCount GPUSize32 = 1;
sampleCount GPUTextureDimension = "2d";
dimension required GPUTextureFormat ;
format required GPUTextureUsageFlags ;
usage sequence <GPUTextureFormat >viewFormats = []; };
viewFormats
, of type sequence<GPUTextureFormat>, defaulting to[]
-
当在此纹理(除了纹理的实际格式
format
)调用createView()
时,指定了何种视图format
值可以被允许。Note: 将格式添加到此列表可能会对性能产生相当大的影响,具体取决于用户的系统。最好避免不必要地添加格式。
此列表中的格式与纹理格式一起必须为纹理视图格式可兼容的。
两个GPUTextureFormat
s format 和 viewFormat 为纹理视图格式可兼容的当:-
format 等于 viewFormat, 或
-
format 和 viewFormat 的区别仅在于它们是否为
srgb
格式(拥有-srgb
后缀)。
定义更大的兼容性类。 [Issue #gpuweb/gpuweb#168]
-
enum {
GPUTextureDimension ,
"1d" ,
"2d" , };
"3d"
typedef [EnforceRange ]unsigned long ; [
GPUTextureUsageFlags Exposed =(Window ,DedicatedWorker )]namespace {
GPUTextureUsage const GPUFlagsConstant = 0x01;
COPY_SRC const GPUFlagsConstant = 0x02;
COPY_DST const GPUFlagsConstant = 0x04;
TEXTURE_BINDING const GPUFlagsConstant = 0x08;
STORAGE_BINDING const GPUFlagsConstant = 0x10; };
RENDER_ATTACHMENT
createTexture(descriptor)
-
创建一个
GPUTexture
.调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createTexture(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUTextureDescriptor
✘ ✘ 针对要创建的 GPUTexture
的描述。返回:
GPUTexture
-
在 this 的设备时间线上执行以下步骤:
-
如果 descriptor.
format
是一个需要某个特性的GPUTextureFormat
(参见 § 25.1 纹理格式功能),但 this.[[device]]
.[[features]]
没有包含该特性,返回TypeError
。 -
如果不满足以下任何要求:
-
descriptor.
usage
必须不为 0。 -
descriptor.
size
.width, descriptor.size
.height, 和 descriptor.size
.depthOrArrayLayers 必须大于零。 -
descriptor.
mipLevelCount
必须大于零。 -
descriptor.
sampleCount
必须为 1 或 4。 -
如果 descriptor.
dimension
是:"1d"
-
-
descriptor.
size
.width 必须小于或等于 this.limits
.maxTextureDimension1D
。 -
descriptor.
size
.depthOrArrayLayers 必须为 1。 -
descriptor.
sampleCount
必须为1。
-
"2d"
-
-
descriptor.
size
.width 必须小于或等于 this.limits
.maxTextureDimension2D
。 -
descriptor.
size
.height 必须小于或等于 this.limits
.maxTextureDimension2D
。 -
descriptor.
size
.depthOrArrayLayers 必须小于或等于 this.limits
.maxTextureArrayLayers
。
-
"3d"
-
-
descriptor.
size
.width 必须小于或等于 this.limits
.maxTextureDimension3D
. -
descriptor.
size
.height 必须小于或等于 this.limits
.maxTextureDimension3D
. -
descriptor.
size
.depthOrArrayLayers 必须小于或等于 this.limits
.maxTextureDimension3D
. -
descriptor.
sampleCount
必须为 1。
-
-
如果 descriptor.
sampleCount
> 1:-
descriptor.
mipLevelCount
必须为 1。 -
descriptor.
size
.depthOrArrayLayers 必须为 1。 -
descriptor.
usage
必须不包含STORAGE_BINDING
位. -
descriptor.
format
必须为可渲染格式并根据 § 25.1 纹理格式功能 支持多重采样。
-
-
descriptor.
mipLevelCount
必须小于或等于 maximum mipLevel count(descriptor.dimension
, descriptor.size
). -
descriptor.
usage
必须为GPUTextureUsage
的值的组合。 -
如果 descriptor.
usage
包含RENDER_ATTACHMENT
位, descriptor.format
必须为可渲染格式. -
If descriptor.
usage
包含STORAGE_BINDING
位, descriptor.format
必须在带有STORAGE_BINDING
功能的 § 25.1.1 纯色格式 表格中列出。
Then:
-
在当前范围内生成带有相应错误消息的
GPUValidationError
。 -
返回一个新的无效
GPUTexture
。
-
让 t 成为一个新的
GPUTexture
对象. -
设定 t.
[[descriptor]]
为 descriptor. -
返回 t.
-
-
const texture= gpuDevice. createTexture({ size: { width: 16 , height: 16 }, format: 'rgba8unorm' , usage: GPUTextureUsage. TEXTURE_BINDING, });
6.1.2. 纹理破坏
不再需要 GPUTexture
的应用程序,可以通过调用 destroy()
选择在垃圾收集之前失去对它的访问权限。
Note: 这允许用户代理在所有先前提交的,并使用了相关的 GPU 内存的操作完成后,回收与 GPUTexture
相关的 GPU 内存。
destroy()
-
摧毁
GPUTexture
.
6.2. GPUTextureView
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUTextureView { };GPUTextureView includes GPUObjectBase ;
GPUTextureView
有以下内部插槽:
[[texture]]
-
这是视图所在的
GPUTexture
。 [[descriptor]]
-
GPUTextureViewDescriptor
描绘这个纹理视图.GPUTextureViewDescriptor
的所有可选字段都已定义。 [[renderExtent]]
-
对于可渲染视图,这是用于渲染的有效
GPUExtent3DDict
。Note: 这个程度取决于
baseMipLevel
.
6.2.1. 纹理视图创建
dictionary :
GPUTextureViewDescriptor GPUObjectDescriptorBase {GPUTextureFormat ;
format GPUTextureViewDimension ;
dimension GPUTextureAspect = "all";
aspect GPUIntegerCoordinate = 0;
baseMipLevel GPUIntegerCoordinate ;
mipLevelCount GPUIntegerCoordinate = 0;
baseArrayLayer GPUIntegerCoordinate ; };
arrayLayerCount
enum {
GPUTextureViewDimension "1d" ,"2d" ,"2d-array" ,"cube" ,"cube-array" ,"3d" , };
"1d"
-
纹理被视为一维图像。 对应 WGSL 类型:
-
texture_1d
-
texture_storage_1d
-
"2d"
-
纹理被视为单二维图像。 对应 WGSL 类型:
-
texture_2d
-
texture_storage_2d
-
texture_multisampled_2d
-
texture_depth_2d
-
texture_depth_multisampled_2d
-
"2d-array"
-
纹理被视为二维图像数组。 对应 WGSL 类型:
-
texture_2d_array
-
texture_storage_2d_array
-
texture_depth_2d_array
-
"cube"
-
纹理被视为立方体贴图。 该视图有 6 个数组层,对应于立方体的 [+X, -X, +Y, -Y, +Z, -Z] 面。
对应 WGSL 类型:
-
texture_cube
-
texture_depth_cube
-
"cube-array"
-
纹理被视为一个包含 n 个立方体贴图的打包阵列,每个贴图有 6 个阵列层,对应于立方体的 [+X, -X, +Y, -Y, +Z, -Z] 面。
对应 WGSL 类型:
-
texture_cube_array
-
texture_depth_cube_array
-
"3d"
-
纹理被视为 3 维图像。
对应 WGSL 类型:
-
texture_3d
-
texture_storage_3d
-
enum {
GPUTextureAspect ,
"all" ,
"stencil-only" , };
"depth-only"
createView(descriptor)
-
创建一个
GPUTextureView
.调用:GPUTexture
this.参数:
Arguments for the GPUTexture.createView(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUTextureViewDescriptor
✘ ✔ 描述要创建的 GPUTextureView
。返回: view,
GPUTextureView
类型。-
设置 descriptor 为带有descriptor 的 resolving GPUTextureViewDescriptor defaults 返回值。
-
在 this 的设备时间线上发布以下指令:
-
如果不满足以下任何要求:
-
this 是有效的
-
如果 descriptor.
aspect
是"stencil-only"
-
this.
[[descriptor]]
.format
必须为一个具有模板宽高比的深度-模板格式。 "depth-only"
-
this.
[[descriptor]]
.format
必须为一个具有深度宽高比的深度-模板格式。
-
descriptor.
mipLevelCount
必须 > 0. -
descriptor.
baseMipLevel
+ descriptor.mipLevelCount
必须 ≤ this.[[descriptor]]
.mipLevelCount
. -
descriptor.
arrayLayerCount
必须 > 0. -
descriptor.
baseArrayLayer
+ descriptor.arrayLayerCount
必须 ≤ the array layer count of this. -
descriptor.
format
必须等于 this.[[descriptor]]
.format
或 this.[[descriptor]]
.viewFormats
中的一个格式。 -
如果 descriptor.
dimension
是:"1d"
-
this.
[[descriptor]]
.dimension
必须是"1d"
.descriptor.
arrayLayerCount
必须是1
. "2d"
-
this.
[[descriptor]]
.dimension
必须是"2d"
.descriptor.
arrayLayerCount
必须是1
. "2d-array"
-
this.
[[descriptor]]
.dimension
必须是"2d"
. "cube"
-
this.
[[descriptor]]
.dimension
必须是"2d"
.descriptor.
arrayLayerCount
必须是6
.this.
[[descriptor]]
.size
.width 必须是 this.[[descriptor]]
.size
.height. "cube-array"
-
this.
[[descriptor]]
.dimension
必须是"2d"
.descriptor.
arrayLayerCount
必须是6
的倍数。this.
[[descriptor]]
.size
.width 必须是 this.[[descriptor]]
.size
.height. "3d"
-
this.
[[descriptor]]
.dimension
必须是"3d"
.descriptor.
arrayLayerCount
必须是1
.
Then:
-
在当前范围内生成一个
GPUValidationError
并带有适当的错误消息。 -
返回一个新的无效
GPUTextureView
。
-
-
让 view 成为一个新的
GPUTextureView
对象。 -
设置 view.
[[texture]]
为 this。 -
设置 view.
[[descriptor]]
为 descriptor. -
如果 this.
[[descriptor]]
.usage
包含RENDER_ATTACHMENT
:-
让 renderExtent 为 compute render extent(this.
[[descriptor]]
.size
, descriptor.baseMipLevel
). -
设置 view.
[[renderExtent]]
为 renderExtent.
-
-
返回 view.
-
-
GPUTextureViewDescriptor
descriptor 运行一下步骤:
-
让 resolved 成为一个 descriptor 的副本。
-
如果 resolved.
format
是undefined
, 设置 resolved.format
为 texture.[[descriptor]]
.format
. -
如果 resolved.
mipLevelCount
是undefined
, 设置 resolved.mipLevelCount
为 texture.[[descriptor]]
.mipLevelCount
−baseMipLevel
. -
如果 resolved.
dimension
是undefined
并且 texture.[[descriptor]]
.dimension
是: -
如果 resolved.
arrayLayerCount
为undefined
并且 resolved.dimension
是:"1d"
,"2d"
, or"3d"
-
设置 resolved.
arrayLayerCount
为1
. "cube"
-
设置 resolved.
arrayLayerCount
为6
. "2d-array"
或者"cube-array"
-
设置 resolved.
arrayLayerCount
为 texture.[[descriptor]]
.size
.depthOrArrayLayers −baseArrayLayer
.
-
返回 resolved.
GPUTexture
texture 的 array layer count,请运行
以下步骤:
-
如果 texture.
[[descriptor]]
.dimension
是:"1d"
或者"3d"
-
返回
1
. "2d"
-
返回 texture.
[[descriptor]]
.size
.depthOrArrayLayers.
-
Let
GPUTextureViewDescriptor
aDescriptor = a.[[descriptor]]
. -
Let
GPUTextureViewDescriptor
bDescriptor = b.[[descriptor]]
. -
Assert: aDescriptor.
mipLevelCount
不为undefined
. -
Assert: bDescriptor.
mipLevelCount
不为undefined
. -
Assert: aDescriptor.
arrayLayerCount
不为undefined
. -
Assert: bDescriptor.
arrayLayerCount
不为undefined
.
当且仅当以下条件为真,两个 GPUTextureView
对象 a 和 b 被作为 texture-view-aliasing
-
a.
[[texture]]
== b.[[texture]]
. -
aDescriptor.
aspect
=="all"
, 或 bDescriptor.aspect
=="all"
, 或 aDescriptor.aspect
== bDescriptor.aspect
. -
aDescriptor.
baseMipLevel
和 aDescriptor.mipLevelCount
构成的区间与 bDescriptor.baseMipLevel
和 bDescriptor.mipLevelCount
构成的区间相交. -
The range formed by aDescriptor.
baseArrayLayer
和 aDescriptor.arrayLayerCount
构成的区间与 bDescriptor.baseArrayLayer
和 bDescriptor.arrayLayerCount
构成的区间相交.
问题: 用“一组子资源”算法来描述这个算法。
6.3. 纹理格式
格式的名称指定了组件的顺序、每个组件的位数、和组件的数据类型。
-
r
,g
,b
,a
= red, green, blue, alpha -
unorm
= unsigned normalized -
snorm
= signed normalized -
uint
= unsigned int -
sint
= signed int -
float
= floating point
如果格式具有 “-srgb” 后缀,则在着色器中读取和写入颜色值期间应用从伽马到线性的 sRGB 转换,反之亦然。 压缩纹理格式由特性提供。其命名应遵循此处的约定,以纹理名称作为前缀。 例如 etc2-rgba8unorm
。
纹素块 是基于像素的 GPUTextureFormat
中纹理的单个可寻址元素,以及基于块的压缩 GPUTextureFormat
中纹理的单个压缩块。
纹素块宽度 和 纹素块高度 指定了一个纹素块的尺寸。
-
对于基于像素的
GPUTextureFormat
s,纹素块宽度和纹素块高度始终为 1。 -
对于基于块压缩的
GPUTextureFormat
s,纹素块宽度是一个纹素块里每一行的纹素数量,纹素块高度是一个纹素块中纹素行的数量。
GPUTextureFormat
的纹素块大小是存储一个纹素块的字节数。
除了 "stencil8"
、"depth24plus"
和 {{GPUTextureFormat/"depth24plus-stencil8"} 之外,每个 GPUTextureFormat
的纹素块大小是恒定的。
enum { // 8-bit 格式
GPUTextureFormat ,
"r8unorm" ,
"r8snorm" ,
"r8uint" , // 16-bit 格式
"r8sint" ,
"r16uint" ,
"r16sint" ,
"r16float" ,
"rg8unorm" ,
"rg8snorm" ,
"rg8uint" , // 32-bit 格式
"rg8sint" ,
"r32uint" ,
"r32sint" ,
"r32float" ,
"rg16uint" ,
"rg16sint" ,
"rg16float" ,
"rgba8unorm" ,
"rgba8unorm-srgb" ,
"rgba8snorm" ,
"rgba8uint" ,
"rgba8sint" ,
"bgra8unorm" , // Packed 32-bit formats
"bgra8unorm-srgb" ,
"rgb9e5ufloat" ,
"rgb10a2unorm" , // 64-bit 格式
"rg11b10ufloat" ,
"rg32uint" ,
"rg32sint" ,
"rg32float" ,
"rgba16uint" ,
"rgba16sint" , // 128-bit 格式
"rgba16float" ,
"rgba32uint" ,
"rgba32sint" , // 深度/模板格式
"rgba32float" ,
"stencil8" ,
"depth16unorm" ,
"depth24plus" ,
"depth24plus-stencil8" , // "depth24unorm-stencil8"特性
"depth32float" , // "depth32float-stencil8"特性
"depth24unorm-stencil8" , // BC 压缩模式非常有用,如果设备和用户代理同时支持 "texture-compression-bc" // 并且在 RequestDevice 中被开启。
"depth32float-stencil8" ,
"bc1-rgba-unorm" ,
"bc1-rgba-unorm-srgb" ,
"bc2-rgba-unorm" ,
"bc2-rgba-unorm-srgb" ,
"bc3-rgba-unorm" ,
"bc3-rgba-unorm-srgb" ,
"bc4-r-unorm" ,
"bc4-r-snorm" ,
"bc5-rg-unorm" ,
"bc5-rg-snorm" ,
"bc6h-rgb-ufloat" ,
"bc6h-rgb-float" ,
"bc7-rgba-unorm" , // 如果设备/用户代理支持并在 requestDevice 中启用 “texture-compression-etc2”,则 ETC2 压缩格式可用。
"bc7-rgba-unorm-srgb" ,
"etc2-rgb8unorm" ,
"etc2-rgb8unorm-srgb" ,
"etc2-rgb8a1unorm" ,
"etc2-rgb8a1unorm-srgb" ,
"etc2-rgba8unorm" ,
"etc2-rgba8unorm-srgb" ,
"eac-r11unorm" ,
"eac-r11snorm" ,
"eac-rg11unorm" , // 如果设备/用户代理支持并在 requestDevice 中启用 “texture-compression-astc”,则 ASTC 压缩格式可用。
"eac-rg11snorm" ,
"astc-4x4-unorm" ,
"astc-4x4-unorm-srgb" ,
"astc-5x4-unorm" ,
"astc-5x4-unorm-srgb" ,
"astc-5x5-unorm" ,
"astc-5x5-unorm-srgb" ,
"astc-6x5-unorm" ,
"astc-6x5-unorm-srgb" ,
"astc-6x6-unorm" ,
"astc-6x6-unorm-srgb" ,
"astc-8x5-unorm" ,
"astc-8x5-unorm-srgb" ,
"astc-8x6-unorm" ,
"astc-8x6-unorm-srgb" ,
"astc-8x8-unorm" ,
"astc-8x8-unorm-srgb" ,
"astc-10x5-unorm" ,
"astc-10x5-unorm-srgb" ,
"astc-10x6-unorm" ,
"astc-10x6-unorm-srgb" ,
"astc-10x8-unorm" ,
"astc-10x8-unorm-srgb" ,
"astc-10x10-unorm" ,
"astc-10x10-unorm-srgb" ,
"astc-12x10-unorm" ,
"astc-12x10-unorm-srgb" ,
"astc-12x12-unorm" , };
"astc-12x12-unorm-srgb"
"depth24plus"
) 和 "depth24plus-stencil8"
) 的深度组件格式可以实现为 24 位无符号归一化值(“depth24unorm”)或 32 位 IEEE 754 浮点值(比如 "depth32float"
)。
在 GPUAdapter(?) 上添加一些东西来估计每像素的字节数 "stencil8"
、"depth24plus-stencil8"
和 "depth32float-stencil8"
。
stencil8
格式可以实现为一个真正的“stencil8”或“depth24stencil8”,其中深度方面是
隐藏且无法访问的。
Note: 虽然对于可表示范围(0.0 到 1.0)中的所有值,depth32float 通道的精度严格高于 depth24unorm 通道的精度,但请注意,可表示值的集合不是精确的超集: 对于 depth24unorm,1 ULP 的常数值为 1 / (224 − 1); 对于 depth32float,1 ULP 的变量值不大于 1 / (224)。
可渲染格式要么是颜色可渲染格式,要么是深度-模板格式。
如果在 § 25.1.1 纯色格式 中列出了具有 RENDER_ATTACHMENT
功能的格式,则它是可渲染颜色的格式。任何其他格式都不是颜色可渲染的格式。所有深度-模板格式都可渲染。
6.4. GPUExternalTexture
GPUExternalTexture
是打包了外部视频对象的可采样纹理。 GPUExternalTexture
对象的内容可能不会改变,无论是从 WebGPU 内部(仅可采样)还是从 WebGPU 外部(例如由于视频帧推进)。
GPUExternalTexture
使用 externalTexture
绑定组布局的输入成员,被绑定到绑定组布局。外部纹理使用多个绑定槽:参见超出绑定槽限制。
外部纹理的底层表示是不可见的(采样行为除外),但通常可能包括
-
最多三个 2D 数据平面(例如 RGBA、Y+UV、Y+U+V)。
-
在从这些平面(裁剪和旋转)读取之前转换坐标的元数据。
-
用于将值转换为指定输出颜色空间(矩阵、伽马、3D LUT)的元数据。
使用的配置可能在时间、系统、用户代理、媒体源、或单个视频源的帧中发生变化。为了用于尽可能多的表示,对于每个外部纹理,绑定保守地使用以下内容:
-
三个采样纹理绑定(最多 3 个平面),
-
一个用于 3D LUT 的采样纹理绑定,
-
一个采样器绑定来采样 3D LUT,以及
-
一种统一的元数据缓冲区绑定。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUExternalTexture { };GPUExternalTexture includes GPUObjectBase ;
GPUExternalTexture
有以下内部插槽:
[[destroyed]]
,boolean
格式-
表示对象是否被摧毁 (不能被使用)。初始被设定为
false
.
6.4.1. 导入外部纹理
外部纹理是使用 importExternalTexture()
从外部视频对象创建的。
外部纹理作为一个微任务,会被自动销毁,而不是像其他资源一样被手动销毁或被当垃圾收集。
dictionary :
GPUExternalTextureDescriptor GPUObjectDescriptorBase {required HTMLVideoElement ;
source GPUPredefinedColorSpace = "srgb"; };
colorSpace
importExternalTexture(descriptor)
-
创建一个
GPUExternalTexture
包装提供的图像源。调用:GPUDevice
this.参数:
Arguments for the GPUDevice.importExternalTexture(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUExternalTextureDescriptor
✘ ✘ 提供外部图像源对象(和任何创建选项)。 -
让 source 成为 descriptor.
source
. -
让 usability 是 检查图像参数的可用性|检查 source 的可用性的结果 (这可能会引发异常)。
-
如果 usability 是
bad
, 返回一个InvalidStateError
并停止运行。 -
如果 source is not origin-clean, 返回一个
SecurityError
并停止运行。 -
让 data 是 source 的当前图像内容转换的结果进入未预乘 alpha 颜色空间 descriptor.
colorSpace
。
此 may result 值超出范围 [0, 1]。如果需要做夹紧保护,可以在取样后进行。
Note: 这被描述为一个副本,但可以作为对只读基础数据的引用,以及稍后执行转换的适当元数据来实现。
-
让 result 是一个新的
GPUExternalTexture
对象包装 data。 -
Queue a microtask 将 result.
[[destroyed]]
设置为true
,并释放底层资源。 -
返回 result.
-
6.4.2. 采样外部纹理
外部纹理在 WGSL 中用 texture_external
表示,可以使用 textureLoad
和 textureSampleLevel
。
提供给 textureSampleLevel
的 sampler
用于对底层纹理进行采样。结果在 colorSpace
设置的颜色空间中。对于任何给定的外部纹理,采样器(和过滤)是在从底层值转换到指定颜色空间之前还是之后应用,这取决于实现。
Note: 如果内部表示是 RGBA 平面,则采样的行为与常规 2D 纹理相同。如果有多个底层平面(例如 Y+UV),则在从 YUV 转换到指定颜色空间之前,使用采样器分别对每个底层纹理进行采样。
7. 采样器
7.1. GPUSampler
一个 GPUSampler
对着色器中的变换和过滤信息进行编码,从而解析了纹理资源数据。
GPUSamplers
通过 GPUDevice.createSampler(optional descriptor)
被创建,返回一个新的采样器对象。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUSampler { };GPUSampler includes GPUObjectBase ;
GPUSampler
有以下内部插槽:
[[descriptor]]
, of typeGPUSamplerDescriptor
, readonly-
用于创建
GPUSampler
的GPUSamplerDescriptor
。 [[isComparison]]
of typeboolean
.-
用于表示 {GPUSampler}} 是否被当作比较采样器。
[[isFiltering]]
of typeboolean
.-
用于表示
GPUSampler
是否对纹理的多个样本进行加权。
7.2. 采样器创建
7.2.1. GPUSamplerDescriptor
GPUSamplerDescriptor
指定用于创建 GPUSampler
的选项。
dictionary :
GPUSamplerDescriptor GPUObjectDescriptorBase {GPUAddressMode = "clamp-to-edge";
addressModeU GPUAddressMode = "clamp-to-edge";
addressModeV GPUAddressMode = "clamp-to-edge";
addressModeW GPUFilterMode = "nearest";
magFilter GPUFilterMode = "nearest";
minFilter GPUFilterMode = "nearest";
mipmapFilter float = 0;
lodMinClamp float = 32;
lodMaxClamp GPUCompareFunction ; [
compare Clamp ]unsigned short = 1; };
maxAnisotropy
-
addressModeU
、addressModeV
,和addressModeW
分别指定纹理宽度、高度和深度坐标的地址模式。 -
magFilter
指定样本足迹小于或等于一个纹素时的采样行为。 -
minFilter
指定样本足迹大于一个纹素时的采样行为。 -
mipmapFilter
指定在两个 mipmap 层之间进行采样的行为。 -
lodMinClamp
和lodMaxClamp
分别指定了细节的最小层级和最大层级,对纹理进行采样时在内部使用。 -
如果提供了
compare
,则采样器将是具有指定GPUCompareFunction
的比较采样器。 -
maxAnisotropy
指定采样器使用的最大各向异性值限制。Note: 大多数实现支持范围在 1 到 16 之间的
maxAnisotropy
值,包括 1 和 16。
GPUAddressMode
描述了采样器在采样足迹超出采样纹理边界时的行为。
enum {
GPUAddressMode "clamp-to-edge" ,"repeat" ,"mirror-repeat" , };
"clamp-to-edge"
-
纹理坐标被限制在 0.0 和 1.0 之间,包括 0.0 和 1.0。
"repeat"
-
纹理坐标换行到纹理的另一侧。
"mirror-repeat"
-
纹理坐标换行到纹理的另一侧,但当坐标的整数部分为奇数时,纹理会翻转。
GPUFilterMode
描述了采样器在样本足迹与一个纹素不完全匹配时的行为。
enum {
GPUFilterMode "nearest" ,"linear" , };
"nearest"
-
返回最接近纹理坐标的纹素值。
"linear"
-
在每个维度中选择两个纹素并返回它们值之间的线性插值。
GPUCompareFunction
指定比较采样器的行为。如果在着色器中使用比较采样器,则将输入值与采样的纹理值进行比较,并将此比较测试的结果(0.0f表示通过,或1.0f表示失败)用于过滤操作。
enum {
GPUCompareFunction "never" ,"less" ,"equal" ,"less-equal" ,"greater" ,"not-equal" ,"greater-equal" ,"always" , };
"never"
-
从不通过比较测试。
"less"
-
如果提供的值小于采样值,则通过比较测试。
"equal"
-
如果提供的值等于采样值,则通过比较测试。
"less-equal"
-
如果提供的值小于等于采样值,则通过比较测试。
"greater"
-
如果提供的值大于采样值,则通过比较测试。
"not-equal"
-
如果提供的值不等于采样值,则通过比较测试。
"greater-equal"
-
如果提供的值大于等于采样值,则通过比较测试。
"always"
-
永远通过比较测试。
-
GPUDevice
device -
GPUSamplerDescriptor
descriptor
返回: boolean
当且仅当满足下列条件时,返回 true
:
-
device 是有效的。
-
descriptor.
lodMinClamp
大于等于 0. -
descriptor.
lodMaxClamp
大于等于 descriptor.lodMinClamp
。 -
descriptor.
maxAnisotropy
大于等于 1。 -
当 descriptor.
maxAnisotropy
大于 1 时,descriptor.magFilter
, descriptor.minFilter
,和 descriptor.mipmapFilter
必须等于"linear"
。
createSampler(descriptor)
-
创建一个
GPUBindGroupLayout
。调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createSampler(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUSamplerDescriptor
✘ ✔ 要创建的 GPUSampler
的描述。返回:
GPUSampler
-
使 s 为一个新的
GPUSampler
对象。 -
将| s|.
[[descriptor]]
设置为 descriptor. -
如果 s.
[[descriptor]]
的compare
属性为null
或者 undefined,将 s.[[isComparison]]
设置为false
,否则,设置为true
。 -
如果
minFilter
,magFilter
或mipmapFilter
中没有一个值为"linear"
,则将 s.[[isFiltering]]
设置为false
,否则,设置为true
。 -
返回 s。
有效使用-
如果 descriptor 不是
null
或 undefined:-
如果 validating GPUSamplerDescriptor(this, descriptor) 返回
false
:-
在当前范围内生成一个
GPUValidationError
并带有恰当的错误消息。 -
返回一个新的无效
GPUSampler
并且返回结果。
-
-
-
GPUSampler
:
const sampler= gpuDevice. createSampler({ addressModeU: 'repeat' , addressModeV: 'repeat' , magFilter: 'linear' , minFilter: 'linear' , mipmapFilter: 'linear' , });
8. 资源绑定
8.1. GPUBindGroupLayout
GPUBindGroupLayout
定义了绑定在 GPUBindGroup
中的一组资源与其在着色器阶段的可访问性之间的接口。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUBindGroupLayout { };GPUBindGroupLayout includes GPUObjectBase ;
GPUBindGroupLayout
有以下内部插槽:
[[descriptor]]
8.1.1. 创建
GPUBindGroupLayout
是通过 GPUDevice.createBindGroupLayout()
创建的。
dictionary :
GPUBindGroupLayoutDescriptor GPUObjectDescriptorBase {required sequence <GPUBindGroupLayoutEntry >; };
entries
GPUBindGroupLayoutEntry
描述了要包含在 GPUBindGroupLayout
中的单个着色器资源绑定。
typedef [EnforceRange ]unsigned long ; [
GPUShaderStageFlags Exposed =(Window ,DedicatedWorker )]namespace {
GPUShaderStage const GPUFlagsConstant = 0x1;
VERTEX const GPUFlagsConstant = 0x2;
FRAGMENT const GPUFlagsConstant = 0x4; };
COMPUTE dictionary {
GPUBindGroupLayoutEntry required GPUIndex32 binding ;required GPUShaderStageFlags visibility ;GPUBufferBindingLayout buffer ;GPUSamplerBindingLayout sampler ;GPUTextureBindingLayout texture ;GPUStorageTextureBindingLayout storageTexture ;GPUExternalTextureBindingLayout externalTexture ; };
GPUBindGroupLayoutEntry
词典有以下成员:
binding
, of type GPUIndex32-
GPUBindGroupLayoutEntry
中资源绑定的唯一标识符、相应的GPUBindGroupEntry
和GPUShaderModule
。 visibility
, of type GPUShaderStageFlags-
GPUShaderStage
成员的比特集。 每个设置位表示GPUBindGroupLayoutEntry
的资源 可以从关联的着色器阶段访问。 buffer
, of type GPUBufferBindingLayout-
当不是
undefined
时,表示这个GPUBindGroupLayoutEntry
的 binding resource type 是GPUBufferBinding
。 sampler
, of type GPUSamplerBindingLayout-
当不是
undefined
时,表示这个GPUBindGroupLayoutEntry
的 binding resource type 是GPUSampler
。 texture
, of type GPUTextureBindingLayout-
当不是
undefined
时,表示这个GPUBindGroupLayoutEntry
的 binding resource type 是GPUTextureView
。 storageTexture
, of type GPUStorageTextureBindingLayout-
当不是
undefined
时,表示这个GPUBindGroupLayoutEntry
的 binding resource type 是GPUTextureView
。 externalTexture
, of type GPUExternalTextureBindingLayout-
当不是
undefined
时,表示这个GPUBindGroupLayoutEntry
的 binding resource type 是GPUExternalTexture
。
GPUBindGroupLayoutEntry
的 binding member 由定义了 GPUBindGroupLayoutEntry
的哪个成员决定: buffer
、sampler
、 texture
、storageTexture
或 externalTexture
。
对于任何给定的 GPUBindGroupLayoutEntry
,只能定义一个。
每个成员都有一个关联的 GPUBindingResource
类型,每个 binding type 都有一个关联的 internal usage,如下表所示:
Binding member | Resource type | Binding type | Binding usage/dfn> |
---|---|---|---|
buffer
| GPUBufferBinding
| "uniform"
| constant |
"storage"
| storage | ||
"read-only-storage"
| storage-read | ||
sampler
| GPUSampler
| "filtering"
| constant |
"non-filtering"
| |||
"comparison"
| |||
texture
| GPUTextureView
| "float"
| constant |
"unfilterable-float"
| |||
"depth"
| |||
"sint"
| |||
"uint"
| |||
storageTexture
| GPUTextureView
| "write-only"
| storage |
externalTexture
| GPUExternalTexture
| constant |
GPUBindGroupLayoutEntry
值的 list entries exceeds the binding slot limitsxi supported limits limits。
每个条目可以使用多个槽来实现多个限制。
-
对于每个 在 entries 中的 entry , 如果:
- entry.
buffer
?.type
是"uniform"
和 entry.buffer
?.hasDynamicOffset
是true
- entry.
buffer
?.type
是"storage"
和 entry.buffer
?.hasDynamicOffset
是true
- entry.
-
对于每个着色器阶段 stage 在 «
VERTEX
,FRAGMENT
,COMPUTE
»:-
对于每个 在 entries 中的 entry , 如果: entry.
visibility
包含 stage, 如果:- entry.
buffer
?.type
是"uniform"
-
1
maxUniformBuffersPerShaderStage
槽会被使用。 - entry.
buffer
?.type
是"storage"
或者"read-only-storage"
-
1
maxStorageBuffersPerShaderStage
槽会被使用。 - entry.
sampler
不是undefined
-
1
maxSamplersPerShaderStage
槽会被使用。 - entry.
texture
不是undefined
-
Consider 1
maxSampledTexturesPerShaderStage
槽会被使用。 - entry.
storageTexture
不是undefined
-
Consider 1
maxStorageTexturesPerShaderStage
槽会被使用。 - entry.
externalTexture
不是undefined
-
4
maxSampledTexturesPerShaderStage
槽, 1maxSamplersPerShaderStage
槽, 和 1maxUniformBuffersPerShaderStage
槽会被使用。
- entry.
-
enum {
GPUBufferBindingType ,
"uniform" ,
"storage" , };
"read-only-storage" dictionary {
GPUBufferBindingLayout GPUBufferBindingType type = "uniform";boolean hasDynamicOffset =false ;GPUSize64 minBindingSize = 0; };
GPUBufferBindingLayout
词典有以下成员:
type
, of type GPUBufferBindingType, defaulting to"uniform"
-
指示绑定到此绑定的缓冲区所需的类型。
hasDynamicOffset
, of type boolean, defaulting tofalse
-
指示此绑定是否需要动态偏移量。
minBindingSize
, of type GPUSize64, defaulting to0
-
指示最小缓冲区绑定大小。
绑定始终在
createBindGroup()
中针对此大小进行验证。如果此 * 不是 *
0
,则额外创建管线 validates,这个值对于着色器中声明的绑定足够大。如果此 * 是 *
0
,则另外绘制/发送命令 validate,GPUBindGroup
中的每个绑定对于着色器中声明的绑定都足够大。
指示最小缓冲区绑定大小。
绑定始终在 createBindGroup()
中针对此大小进行验证。
如果此 * 不是 * 0
,则额外创建管道 validates 这个值对于着色器中声明的绑定足够大。
如果此 * 是 * 0
,则另外绘制/发送命令 validate GPUBindGroup
中的每个绑定对于着色器中声明的绑定都足够大。
注意:对于为早期验证指定的其他绑定相关字段,类似的执行时间验证在理论上是可能的,例如 sampleType
和 format
,目前只能在管线创建中进行验证。然而,这种执行时间验证可能成本高昂或不必要地复杂,因此它仅适用于预计具有最符合人体工程学影响的 minBindingSize
。
enum {
GPUSamplerBindingType ,
"filtering" ,
"non-filtering" , };
"comparison" dictionary {
GPUSamplerBindingLayout GPUSamplerBindingType type = "filtering"; };
GPUSamplerBindingLayout
词典有以下成员:
type
, of type GPUSamplerBindingType, defaulting to"filtering"
-
指示绑定到此绑定的采样器的所需类型。
enum {
GPUTextureSampleType ,
"float" ,
"unfilterable-float" ,
"depth" ,
"sint" , };
"uint" dictionary {
GPUTextureBindingLayout GPUTextureSampleType sampleType = "float";GPUTextureViewDimension viewDimension = "2d";boolean multisampled =false ; };
问题(https://github.com/gpuweb/gpuweb/issues/851): 如何使 sampleType
真正可选。
GPUTextureBindingLayout
词典有以下成员:
sampleType
, of type GPUTextureSampleType, defaulting to"float"
-
指示绑定到此绑定的纹理视图所需的类型。
viewDimension
, of type GPUTextureViewDimension, defaulting to"2d"
-
指示绑定到此绑定的纹理视图所需的
dimension
。 multisampled
, of type boolean, defaulting tofalse
-
指示绑定到此绑定的纹理视图是否必须进行多重采样。
enum {
GPUStorageTextureAccess , };
"write-only" dictionary {
GPUStorageTextureBindingLayout GPUStorageTextureAccess access = "write-only";required GPUTextureFormat format ;GPUTextureViewDimension viewDimension = "2d"; };
问题(https://github.com/gpuweb/gpuweb/issues/851): 考虑时 format
真正可选。
GPUStorageTextureBindingLayout
词典有以下成员:
access
, of type GPUStorageTextureAccess, defaulting to"write-only"
-
指示绑定到此绑定的纹理视图是否将绑定为只读或 只写访问。
format
, of type GPUTextureFormat-
绑定到此绑定的纹理视图所需的
format
。 viewDimension
, of type GPUTextureViewDimension, defaulting to"2d"
-
指示绑定到此绑定的纹理视图所需的
dimension
。
dictionary { };
GPUExternalTextureBindingLayout
GPUBindGroupLayout
对象有以下内部插槽:
[[entryMap]]
是 ordered map<GPUSize32
,GPUBindGroupLayoutEntry
> 类型。-
指向
GPUBindGroupLayoutEntry
的绑定索引映射,此GPUBindGroupLayout
描述了该映射。 [[dynamicOffsetCount]]
是GPUSize32
类型。-
此
GPUBindGroupLayout
中具有动态偏移量的缓冲区绑定数。 [[exclusivePipeline]]
GPUPipelineBase
类型?, 初始设定为null
。-
创建此
GPUBindGroupLayout
的管道,如果它是作为 default pipeline layout 的一部分创建的。 如果不是null
,则使用此GPUBindGroupLayout
创建的GPUBindGroup
只能与指定的GPUPipelineBase
一起使用。
createBindGroupLayout(descriptor)
-
创建一个
GPUBindGroupLayout
。调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createBindGroupLayout(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUBindGroupLayoutDescriptor
✘ ✘ 要创建的 GPUBindGroupLayout
的描述。-
让 layout 是一个新的有效
GPUBindGroupLayout
对象。 -
设置 layout.
[[descriptor]]
为 descriptor. -
在 this 的 Device timeline 上发出以下步骤:
-
如果一下任一条件没有被满足:
-
在 descriptor 中每一个条目的
binding
是唯一的。 -
descriptor 中每个条目的
binding
必须 < 65536。 -
descriptor.
entries
必须不能 超过绑定槽限制|超过 this.[[device]]
.[[limits]]
的绑定槽限制。 -
descriptor.
entries
中每一个条目的GPUBindGroupLayoutEntry
:-
设定 bufferLayout 为 entry.
buffer
-
设定 samplerLayout 为 entry.
sampler
-
设定 textureLayout 为 entry.
texture
-
设定 storageTextureLayout 为 entry.
storageTexture
-
bufferLayout, samplerLayout, textureLayout, 或 storageTextureLayout 其中一个不是
undefined
。 -
如果 entry.
visibility
包含VERTEX
:-
entry.
storageTexture
?.access
必须不能是"write-only"
.
-
如果 textureLayout 不是
undefined
并且 textureLayout.multisampled
是true
:-
textureLayout.
viewDimension
是"2d"
. -
textureLayout.
sampleType
不是"float"
或者"depth"
.
-
-
如果 storageTextureLayout 不是
undefined
:-
storageTextureLayout.
viewDimension
不是"cube"
或"cube-array"
. -
storageTextureLayout.
format
必须是可以支持存储使用的格式。
-
-
Then:
-
在当前范围内产生一个带有适当错误消息的
GPUValidationError
。 -
使 layout invalid 并且返回 layout。
-
Set layout.
[[dynamicOffsetCount]]
to the number of entries in descriptor wherebuffer
is notundefined
andbuffer
.hasDynamicOffset
istrue
. -
For each
GPUBindGroupLayoutEntry
entry in descriptor.entries
:-
Insert entry into layout.
[[entryMap]]
with the key of entry.binding
.
-
-
-
返回 layout.
-
8.1.2. 兼容性
GPUBindGroupLayout
对象 a 和 b 是 group-equivalent 当且仅当满足以下所有条件:
-
对于任何绑定编号binding,满足以下条件之一:
-
编号在 a.
[[entryMap]]
和 b.[[entryMap]]
中都丢失了。 -
a.
[[entryMap]]
[binding] == b.[[entryMap]]
[binding]
-
如果绑定组布局是 group-equivalent,它们可以在所有内容中互换使用。
8.2. GPUBindGroup
GPUBindGroup
定义了一组要绑定到一个组中的资源
以及如何在着色器阶段使用资源。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUBindGroup { };GPUBindGroup includes GPUObjectBase ;
8.2.1. 绑定组创建
一个 GPUBindGroup
通过 GPUDevice.createBindGroup()
被创建。
dictionary :
GPUBindGroupDescriptor GPUObjectDescriptorBase {required GPUBindGroupLayout ;
layout required sequence <GPUBindGroupEntry >; };
entries
GPUBindGroupEntry
描述了要绑定在 GPUBindGroup
中的单个资源。
typedef (GPUSampler or GPUTextureView or GPUBufferBinding or GPUExternalTexture );
GPUBindingResource dictionary {
GPUBindGroupEntry required GPUIndex32 ;
binding required GPUBindingResource ; };
resource
dictionary {
GPUBufferBinding required GPUBuffer ;
buffer GPUSize64 = 0;
offset GPUSize64 ; };
size
一个 GPUBindGroup
对象有以下内部插槽:
[[layout]]
GPUBindGroupLayout
类型。-
与此
GPUBindGroup
关联的GPUBindGroupLayout
。 [[entries]]
是类型序列 <GPUBindGroupEntry
>.-
此
GPUBindGroup
描述的GPUBindGroupEntry
集。 [[usedResources]]
是 ordered map<subresource, list<internal usage>> 类型。-
此绑定组使用的缓冲区和纹理集 subresource, 与 internal usage 标志的列表相关联。
createBindGroup(descriptor)
-
创建一个
GPUBindGroup
.调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createBindGroup(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUBindGroupDescriptor
✘ ✘ Description of the GPUBindGroup
to create.返回:
GPUBindGroup
-
设定 bindGroup 为一个新的有效的
GPUBindGroup
对象。 -
设定 limits 为 this.
[[device]]
.[[limits]]
。 -
在 this 的 Device timeline 发布一下步骤:
-
如果以下任一条件没有被满足:
对于每一个 descriptor.
entries
中的GPUBindGroupEntry
bindingDescriptor:-
设定 resource 为 bindingDescriptor.
resource
。 -
在 descriptor.
layout
.entries
中, 只有一个GPUBindGroupLayoutEntry
layoutBinding 使得 layoutBinding.binding
等于 bindingDescriptor.binding
。 -
如果为 layoutBinding 定义了 binding member 是
sampler
-
-
resource 是一个
GPUSampler
. -
resource 与 this 一起使用是有效的。
-
如果 layoutBinding.
sampler
.type
是:"filtering"
-
resource.
[[isComparison]]
是false
. "non-filtering"
-
resource.
[[isFiltering]]
是false
. resource.[[isComparison]]
是false
. "comparison"
-
resource.
[[isComparison]]
是true
.
-
texture
-
-
resource 是一个
GPUTextureView
。 -
resource 与 this 一起使用是有效的。
-
设置 texture 为 resource.
[[texture]]
. -
layoutBinding.
texture
.viewDimension
与 resource 的dimension
相等。 -
layoutBinding.
texture
.sampleType
是与 resource 的format
兼容的。 -
texture 的
usage
包含TEXTURE_BINDING
. -
如果 layoutBinding.
texture
.multisampled
是true
, texture 的sampleCount
>1
, 否则 texture 的sampleCount
为1
.
-
storageTexture
-
-
resource 是一个
GPUTextureView
。 -
resource 与 this 一起使用是有效的。
-
设置 texture 为 resource.
[[texture]]
. -
layoutBinding.
storageTexture
.viewDimension
与 resource 的dimension
相同。 -
layoutBinding.
storageTexture
.format
与 resource.[[descriptor]]
.format
相等。 -
texture 的
usage
包含STORAGE_BINDING
。 -
resource.
[[descriptor]]
.mipLevelCount
必须为1。
-
buffer
-
-
resource 是一个
GPUBufferBinding
. -
resource.
buffer
与 this 一起使用是有效的。 -
effective buffer binding size(resource),大于或等于layoutBinding.
buffer
.minBindingSize
. -
有效绑定大小,即在 resource.
size
或派生自 resource.offset
和完整的 缓冲区的大小,大于或等于 layoutBinding.buffer
.minBindingSize
. -
如果 layoutBinding.
buffer
.type
是"uniform"
-
resource.
buffer
.usage
包含UNIFORM
。effective buffer binding size(resource) ≤ limits.
maxUniformBufferBindingSize
。resource.
offset
是 limits.minUniformBufferOffsetAlignment
的倍数。问题:当
size
未设置时,此验证应考虑默认值。 还应该size
默认为buffer.byteLength - offset
或min(buffer.byteLength - offset, limits.maxUniformBufferBindingSize)
? "storage"
或者"read-only-storage"
-
resource.
buffer
.usage
包含STORAGE
。effective buffer binding size(resource) ≤ limits.
maxStorageBufferBindingSize
.resource.
offset
是 limits.minStorageBufferOffsetAlignment
的倍数。 externalTexture
-
-
resource是一个
GPUExternalTexture
. -
resource valid to use with this.
-
-
Then:
-
在当前范围内产生一个带有适当错误消息的
GPUValidationError
。 -
使 bindGroup invalid 并返回 bindGroup.
-
-
设置 bindGroup.
[[layout]]
= descriptor.layout
. -
设置 bindGroup.
[[entries]]
= descriptor.entries
. -
设置 bindGroup.
[[usedResources]]
= {}. -
descriptor.
entries
中的每一个GPUBindGroupEntry
bindingDescriptor:-
设定 internalUsage 为 binding usage 为了 layoutBinding。
-
resource 看到的每个 subresource 添加到
[[usedResources]]
作为 internalUsage。
-
-
-
返回 bindGroup.
问题:单独定义“有效缓冲区绑定大小”。
-
GPUBufferBinding
对象 a 和 b 被作为 buffer-binding-aliasing:
问题:定义当大小可以为 undefined 时区间如何被 offset/size 构成。
8.3. GPUPipelineLayout
GPUPipelineLayout
定义了在 setBindGroup
中的命令编码期间设置的所有 GPUBindGroup
对象的资源和由设置的管道着色器之间的映射GPURenderEncoderBase.setPipeline
或 GPUComputePassEncoder.setPipeline
。
资源的完整绑定地址可以定义为以下三项:
-
着色器阶段蒙版,资源可见
-
绑定组索引
-
绑定号码
这个地址的组成部分也可以看作是一个管道的绑定空间。 GPUBindGroup
(带有相应的 GPUBindGroupLayout
)覆盖了固定绑定组索引的空间。 包含的绑定需要是着色器在此绑定组索引处使用的资源的超集。
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUPipelineLayout { };GPUPipelineLayout includes GPUObjectBase ;
GPUPipelineLayout
有以下内部插槽:
[[bindGroupLayouts]]
list<GPUBindGroupLayout
> 类型。-
在
GPUPipelineLayoutDescriptor.bindGroupLayouts
中创建时提供的GPUBindGroupLayout
对象。
注意:对许多 GPURenderPipeline
或 GPUComputePipeline
管道使用相同的 GPUPipelineLayout
可以保证用户代理在这些管道之间切换时不需要在内部重新绑定任何资源。
GPUComputePipeline
对象 X 是由 GPUPipelineLayout.bindGroupLayouts
A, B, C 创建。 GPUComputePipeline
对象 Y 是由 GPUPipelineLayout.bindGroupLayouts
A, D, C 创建。
假设命令编码序列有两个调度:
在这种情况下,用户代理将不得不重新绑定组插槽 2 以进行第二次调度,
即使 GPUPipelineLayout.bindGrouplayouts
的索引 2 处的 GPUBindGroupLayout
,
或插槽 2 处的 GPUBindGroup
更改。
问题:是否应将此示例和注释移至某些“最佳实践”文档?
注意:GPUPipelineLayout
的预期用途是将最常见和最不频繁更改的绑定组放置在布局的“底部”,这意味着较低的绑定组插槽编号,例如 0 或 1。
绑定越频繁 group 需要在 draw call 之间改变,它的索引应该越高。
这个通用指南允许用户代理最小化绘制调用之间的状态变化,从而降低 CPU 开销。
8.3.1. 创建
GPUPipelineLayout
是通过 GPUDevice.createPipelineLayout()
创建的。
dictionary :
GPUPipelineLayoutDescriptor GPUObjectDescriptorBase {required sequence <GPUBindGroupLayout >; };
bindGroupLayouts
createPipelineLayout(descriptor)
-
创建一个
GPUPipelineLayout
。调用:GPUDevice
this。参数:
Arguments for the GPUDevice.createPipelineLayout(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUPipelineLayoutDescriptor
✘ ✘ 要创建的 GPUPipelineLayout
的描述。-
如果以下任一条件为满足:
设定 limits 为 this.[[device]]
.[[limits]]
。让 allEntries 是连接 descriptor.
bindGroupLayouts
中所有 bgl 的 bgl.[[descriptor]]
.entries
的结果。-
descriptor.
bindGroupLayouts
中的每个GPUBindGroupLayout
必须与 this 一起使用是有效的, 并且[[exclusivePipeline]]
为null
。 -
descriptor.
bindGroupLayouts
的 size 必须 ≤ limits.maxBindGroups
。 -
allEntries 必须不能超过绑定槽限制|超过绑定槽限制 limits。
Then:
-
在当前范围内产生一个带有适当错误消息的
GPUValidationError
。 -
创建一个新的 invalid
GPUPipelineLayout
并返回结果。
-
-
设定 pl 为一个新的
GPUPipelineLayout
对象。 -
设定 pl.
[[bindGroupLayouts]]
为 descriptor.bindGroupLayouts
。 -
返回 pl。
-
注意:两个 GPUPipelineLayout
对象对于任何用法都被认为是等效的
如果它们的内部 [[bindGroupLayouts]]
序列包含 GPUBindGroupLayout
对象是 group-equivalent。
8.4. Example
GPUBindGroupLayout
,之后使用 GPUBindGroupLayout
创建 GPUBindGroup
和 GPUPipelineLayout
。
const bindGroupLayout= gpuDevice. createBindGroupLayout({ entries: [{ binding: 0 , visibility: GPUShaderStage. VERTEX| GPUShaderStage. FRAGMENT, buffer: {} }, { binding: 1 , visibility: GPUShaderStage. FRAGMENT, texture: {} }, { binding: 2 , visibility: GPUShaderStage. FRAGMENT, sampler: {} }] }); const bindGroup= gpuDevice. createBindGroup({ layout: bindGroupLayout, entries: [{ binding: 0 , resource: { buffer: buffer}, }, { binding: 1 , resource: texture}, { binding: 2 , resource: sampler}] }); const pipelineLayout= gpuDevice. createPipelineLayout({ bindGroupLayouts: [ bindGroupLayout] });
9. 着色器模块
9.1. GPUShaderModule
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUShaderModule {Promise <GPUCompilationInfo >compilationInfo (); };GPUShaderModule includes GPUObjectBase ;
GPUShaderModule
是对内部着色器模块对象的引用。
问题(gpuweb/gpuweb#354): 完成定义多线程API并将 [Serializable]
添加回接口。
9.1.1. 着色器模块创建
dictionary {
GPUShaderModuleCompilationHint required GPUPipelineLayout ; };
layout dictionary :
GPUShaderModuleDescriptor GPUObjectDescriptorBase {required USVString ;
code object ;
sourceMap record <USVString ,GPUShaderModuleCompilationHint >; };
hints
sourceMap
,如果定义,可以解释为source-map-v3格式。Source maps是可选的,但它作为支持开发工具集成(例如源语言调试)的标准化方法。 hints
,如果已定义,则将着色器的入口点名称映射到 GPUShaderModuleCompilationHint
。
不使用任何这些 GPUShaderModuleCompilationHint
执行验证。
实现应使用 GPUShaderModuleCompilationHint
中存在的任何信息在 createShaderModule()
中执行尽可能多的编译。
注意:在 hints
中提供信息除了性能之外没有任何可观察到的影响。因为单个着色器模块可以容纳多个入口点,并且可以从单个着色器模块创建多个管线,所以实现在 createShaderModule()
中进行尽可能多的编译可以提高性能,而不是在对 createComputePipeline()
/ createRenderPipeline()
的多次调用中多次调用。
注意:如果可能,作者应该向 createShaderModule()
和 createComputePipeline()
/ createRenderPipeline()
提供相同的信息。
注意:如果作者在调用 createShaderModule()
时无法提供此 hints
信息,通常不应延迟调用 createShaderModule()
;但应该只是省略 hints
或 GPUShaderModuleCompilationHint
中的未知信息。省略此信息可能会导致编译推迟到 createComputePipeline()
/ createRenderPipeline()
。
注意:如果作者不确定传递给 createShaderModule()
的信息是否与稍后传递给 createComputePipeline()
/ createRenderPipeline()
的信息匹配同一个模块,他们应该避免将该信息传递给 createShaderModule()
,因为将不匹配的信息传递给 createShaderModule()
可能会导致发生不必要的编译。
createShaderModule(descriptor)
-
创建一个
GPUShaderModule
.Called on:GPUDevice
this.Arguments:
Arguments for the GPUDevice.createShaderModule(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUShaderModuleDescriptor
✘ ✘ 要创建的 GPUShaderModule
的描述。Returns:
GPUShaderModule
问题:描述
createShaderModule()
算法步骤。
GPUShaderModule
:
// A simple vertex and fragment shader pair that will fill the viewport with red. const shaderSource= ` var<private> pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>( vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); @stage(vertex) fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> @builtin(position) vec4<f32> { return vec4(pos[input.vertexIndex], 1.0, 1.0); } @stage(fragment) fn fragmentMain() -> @location(0) vec4<f32> { return vec4(1.0, 0.0, 0.0, 1.0); } ` ; const shaderModule= gpuDevice. createShaderModule({ code: shaderSource, });
9.1.2. 着色器模块编译信息
enum {
GPUCompilationMessageType ,
"error" ,
"warning" , }; [
"info" Exposed =(Window ,DedicatedWorker ),Serializable ,SecureContext ]interface {
GPUCompilationMessage readonly attribute DOMString message ;readonly attribute GPUCompilationMessageType type ;readonly attribute unsigned long long lineNum ;readonly attribute unsigned long long linePos ;readonly attribute unsigned long long offset ;readonly attribute unsigned long long length ; }; [Exposed =(Window ,DedicatedWorker ),Serializable ,SecureContext ]interface {
GPUCompilationInfo readonly attribute FrozenArray <GPUCompilationMessage >; };
messages
GPUCompilationMessage
是由GPUShaderModule
编译器生成的信息、警告或错误消息。 这些消息旨在让人类可读,以帮助开发人员诊断着色器code
的问题。每个消息可能对应于着色器代码中的单个点、着色器代码的子串,或者可能根本不对应于代码中的任何特定点。
GPUCompilationMessage
具有以下属性:
message
, of type DOMString, readonly-
一个人类可读的包含着色器编译时产生的消息的字符串。
type
, of type GPUCompilationMessageType, readonly-
消息的重要性级别。
如果
type
错误,它对应着一个shader-creation error。 lineNum
, of type unsigned long long, readonly-
message
对应的着色器代码中的行号。值是one-based,这样lineNum为1表示着色器code
的第一行。如果
message
对应于子字符串,则它指向子字符串开始的行。如果消息不对应着色器代码中的任何特定点,则必须为0。问题(gpuweb/gpuweb#2435): 在[定义行是什么]时参考WGSL规范(https://gpuweb.github.io/gpuweb/wgsl/#comments)。
linePos
, of type unsigned long long, readonly-
从着色器
code
的lineNum
行的开头到message
对应的子字符串的点或开头的偏移量,以UTF-16代码单元为单位。值是one-based,这样linePos
为1表示该行的第一个字符。如果
message
对应于子字符串,则它指向子字符串的第一个UTF-16代码单元。如果消息不对应着色器代码中的任何特定点,则必须为0。 offset
, of type unsigned long long, readonly-
从UTF-16代码单元中的着色器
code
的开头到message
对应的子字符串的点或开头的偏移量。必须引用与lineNum
和linePos
相同的位置。如果message
不对应着色器code
中的任何特定点,则必须为0。 length
, of type unsigned long long, readonly
注意:GPUCompilationMessage
.lineNum
和 GPUCompilationMessage
.linePos
是one-based,因为它们最常见的用途是打印人类可读的消息,这些消息可以与许多文本编辑器中显示的行号和列号相关联。
注意:GPUCompilationMessage
.offset
和GPUCompilationMessage
.length
适合传递给 substr()
以检索message
对应的着色器code
的子字符串。
compilationInfo()
-
返回
GPUShaderModule
编译时产生的任何消息。消息的位置、顺序和内容是实现定义的。特别是,消息可能不会按
lineNum
排序。
10. 管道
一个 管线,无论是 GPUComputePipeline
还是 GPURenderPipeline
,
表示由 GPU 硬件、驱动程序、
和用户代理,以绑定和顶点缓冲区的形式处理输入数据,
并产生一些输出,如输出渲染目标中的颜色。
在结构上,pipeline 由一系列可编程阶段(着色器)组成 和固定功能状态,例如混合模式。
注意:在内部,取决于目标平台, 驱动程序可能会将一些固定功能状态转换为着色器代码, 并将其与用户提供的着色器链接在一起。 这种链接是将对象作为一个整体创建的原因之一。
此组合状态创建为单个对象
(通过 GPUDevice.createComputePipeline()
或 GPUDevice.createRenderPipeline()
),
并切换为一个
(相应地通过 GPUComputePassEncoder.setPipeline
或 GPURenderEncoderBase.setPipeline
)。
10.1. 基础管道
dictionary :
GPUPipelineDescriptorBase GPUObjectDescriptorBase {GPUPipelineLayout ; };
layout interface mixin {
GPUPipelineBase GPUBindGroupLayout getBindGroupLayout (unsigned long index ); };
GPUPipelineBase
有以下内部插槽:
[[layout]]
of typeGPUPipelineLayout
.-
可以与
this
一起使用的资源布局的定义.
GPUPipelineBase
有以下方法:
getBindGroupLayout(index)
-
获取一个
GPUBindGroupLayout
,它与index
处的GPUPipelineBase
的GPUBindGroupLayout
兼容。调用:GPUPipelineBase
this.参数:
Arguments for the GPUPipelineBase.getBindGroupLayout(index) method. Parameter Type Nullable Optional Description index
unsigned long
✘ ✘ 对管道布局的 [[bindGroupLayouts]]
序列的索引。-
如果 index ≥ this.
[[device]]
.[[limits]]
.maxBindGroups
:-
抛出一个
RangeError
.
-
-
如果 this 不是 valid:
-
返回一个新的错误的
GPUBindGroupLayout
.
-
-
返回一个新的
GPUBindGroupLayout
对象引用相同的内部对象 this.[[layout]]
.[[bindGroupLayouts]]
[index].
问题:一旦我们拥有
GPUBindGroupLayout
的内部对象,请更正确地指定此项。 或者,只有规范作为 group-equivalent 的新内部对象注意:仅返回新的
GPUBindGroupLayout
对象可确保 Content timeline 和 Device timeline 之间不需要同步。 -
10.1.1. 默认管道布局
在没有 layout
的情况下创建的 GPUPipelineBase
对象具有创建和使用的默认布局。
要为 GPUPipelineBase
pipeline 创建 default pipeline layout,
运行以下步骤:
-
让 groupDescs 是一系列 device.
[[limits]]
.maxBindGroups
新的GPUBindGroupLayoutDescriptor
对象。 -
对于每个在 groupDescs 中的 groupDesc:
-
设置 groupDesc.
entries
为一个空序列。
-
-
对于每个
GPUProgrammableStage
stageDesc 在用于创建 pipeline 的描述符中:-
让 stageInfo 是 stageDesc 的“反射信息”。
问题:定义反射信息概念,以便此规范可以与 WGSL 规范接口,并获取特定入口点的
GPUShaderModule
接口的信息。 -
让 shaderStage 成为 stageDesc.
module
中 stageDesc.entryPoint
的GPUShaderStageFlags
。 -
对于每个资源 resource 在 stageInfo 的资源接口中:
-
让 group 成为 resource 的 “group” 装饰。
-
让 binding 成为 resource 的 "binding" 装饰。
-
让 entry 成为一个新的
GPUBindGroupLayoutEntry
. -
设定 entry.
binding
为 binding. -
设定 entry.
visibility
为 shaderStage. -
如果 resource 用于采样器绑定:
-
让 samplerLayout 成为一个新的
GPUSamplerBindingLayout
. -
设置 entry.
sampler
为 samplerLayout.
-
-
如果 resource 用于比较采样器绑定:
-
让 samplerLayout 成为一个新的
GPUSamplerBindingLayout
. -
设置 samplerLayout.
type
为"comparison"
. -
设置 entry.
sampler
为 samplerLayout.
-
-
如果 resource 用于缓冲区绑定:
-
让 bufferLayout 成为一个新的
GPUBufferBindingLayout
. -
设置 bufferLayout.
minBindingSize
为 resource 的缓冲区绑定大小的最小值.问题:链接到“反射信息”中“最小缓冲区绑定大小”的定义。
-
如果 resource 用于只读存储缓冲区:
-
设定 bufferLayout.
type
为"read-only-storage"
.
-
-
如果 resource 用于存储缓冲区:
-
设置 entry.
buffer
为 bufferLayout.
-
-
如果 resource 用于采样纹理绑定:
-
设置 textureLayout 为一个新的
GPUTextureBindingLayout
. -
如果 resource 用于深度采样纹理绑定:
-
设置 textureLayout.
sampleType
为"depth"
如果 resource 的采样类型是:
-
f32
并且 resource 与着色器中内置的 textureSample* 静态使用-
设置 textureLayout.
sampleType
为"float"
f32
-
设置 textureLayout.
sampleType
为"unfilterable-float"
i32
-
设置 textureLayout.
sampleType
为"sint"
u32
-
设置 textureLayout.
sampleType
为"uint"
-
-
设置 textureLayout.
viewDimension
为 resource 的维度。 -
如果 resource 用于多重采样纹理:
-
设置 textureLayout.
multisampled
为true
.
-
-
设置 entry.
texture
为 textureLayout.
-
-
如果 resource 用于存储纹理绑定:
-
让 storageTextureLayout 成为一个新的
GPUStorageTextureBindingLayout
。 -
设置 storageTextureLayout.
format
为 resource 的格式。 -
设置 storageTextureLayout.
viewDimension
为 resource 的维度。 -
如果 resource 用于只写存储纹理:
-
设置 storageTextureLayout.
access
为"write-only"
。
-
-
设置 entry.
storageTexture
为 storageTextureLayout。
-
-
如果 groupDescs[group] 有一个条目 previousEntry
binding
等于 binding:-
如果 entry 具有与 previousEntry 不同的
visibility
:-
将 entry.
visibility
中设置的位添加到 previousEntry.visibility
-
-
如果 resource 用于缓冲区绑定和 entry 有比 previousEntry 更大的
buffer
.minBindingSize
:-
设置 previousEntry.
buffer
.minBindingSize
为 entry.buffer
.minBindingSize
。
-
-
如果 resource 是一个采样的纹理绑定和 entry 具有与 previousEntry 不同的
texture
.sampleType
并且两者 entry 和 previousEntry 有texture
.sampleType
或"float"
或"unfilterable-float"
:-
设置 previousEntry.
texture
.sampleType
为"float"
.
-
-
如果任何其他属性在 entry 之间不相等 和 previousEntry:
-
返回
null
(这将导致管道的创建失败)。
-
-
-
其他
-
附加 entry 到 groupDescs[group]。
-
-
-
-
让 groupLayouts 成为一个新的序列。
-
对于每一个在 groupDescs 中的 groupDesc:
-
让 bindGroupLayout 成为调用 device.
createBindGroupLayout()
(groupDesc) 的结果。 -
设置 bindGroupLayout.
[[exclusivePipeline]]
为 pipeline。 -
附加 bindGroupLayout 到 groupLayouts。
-
-
让 desc 成为一个新的
GPUPipelineLayoutDescriptor
。 -
设置 desc.
bindGroupLayouts
为 groupLayouts。 -
返回 device.
createPipelineLayout()
(desc)。
问题:这会用空的绑定组填充管道布局。 一旦指定了空绑定组的行为,请重新访问。
10.1.2. GPUProgrammableStage
GPUProgrammableStage
描述了用户提供的 GPUShaderModule
中的入口点,该入口点控制 pipeline 的可编程阶段之一。
dictionary GPUProgrammableStage {required GPUShaderModule ;
module required USVString ;
entryPoint record <USVString ,GPUPipelineConstantValue >constants ; };typedef double GPUPipelineConstantValue ; // May represent WGSL’s bool, f32, i32, u32.
constants
, of type record<USVString, GPUPipelineConstantValue>-
指定着色器模块
module
中 pipeline-overridable 常量的值。每个这样的 pipeline-overridable 常量都由单个 [=pipeline-overridable constant identifier string==] 唯一标识(表示常量的数字 ID,如果指定了一个,否则表示常量的标识符名称)。
每个键值对的键必须等于一个这样的常量的标识符字符串。 执行管道时,该常量将具有指定的值。
值被指定为
GPUPipelineConstantValue
,它是一个double
, 它被转换为相应管道可覆盖常量的 WGSL 数据类型(bool
、i32
、u32
、 或f32
) 通过 [=converted to an IDL value|an IDL value=|一个 IDL 值=]boolean
、long
、unsigned long
或float
)。Pipeline-overridable constants defined in WGSL:@ override ( 0 ) let has_point_light :bool = true ; // Algorithmic control. @ override ( 1200 ) let specular_param :f32 = 2.3 ; // Numeric control. @ override ( 1300 ) let gain :f32 ; // Must be overridden. @ override let width :f32 = 0.0 ; // Specifed at the API level // using the name "width". @ override let depth :f32 ; // Specifed at the API level // using the name "depth". // Must be overridden. 相应的 JavaScript 代码,仅提供所需的覆盖 (没有默认值):
{ // ... constants: { 1300 : 2.0 , // "gain" depth: - 1 , // "depth" } } Corresponding JavaScript code, overriding all constants:
{ // ... constants: { 0 : false , // "has_point_light" 1200 : 3.0 , // "specular_param" 1300 : 2.0 , // "gain" width: 20 , // "width" depth: - 1 , // "depth" } }
参数:
-
GPUShaderStage
stage -
GPUProgrammableStage
descriptor -
GPUPipelineLayout
layout
如果满足以下所有条件,则返回 true
:
-
descriptor.
module
必须是一个 validGPUShaderModule
. -
descriptor.
module
必须包含 一个入口点,用于着色器阶段 stage, 名为 descriptor.entryPoint
。 -
对于每个 binding 即着色器入口点的 statically used :
-
validating shader binding(binding, layout) 必须返回
true
。
-
-
对于入口点 statically used 的每个纹理采样着色器调用:
-
让 texture 是与调用中的采样纹理对应的
GPUBindGroupLayoutEntry
。 -
让 sampler 是与调用中使用的采样器对应的
GPUBindGroupLayoutEntry
。 -
如果 sampler.
type
是"filtering"
, 那么 texture.sampleType
必须不是"unfilterable-float"
。
-
-
对于每个 key 在 descriptor.
constants
的 the keys 中:-
key 必须等于在着色器模块 descriptor.
module
中定义的某些 pipeline-overridable 常量的 pipeline-overridable constant identifier string,通过代码点,而不是 !UnicodeVersion14|Unicode Version 14.0.0 的 UAX15 Equivalences
Note: 用户代理应考虑在大多数或所有情况下发出开发人员可见的警告,其中显示具有不同代码点序列的两个名称在读者看来是相同的,例如在规范下与 Normalization Form C (NFC) 等价或看起来相似的字符。
-
key 必须等于着色器模块中定义的某些 pipeline-overridable 的 pipeline-overridable constant identifier string descriptor.
module
。
-
-
对于每个 pipeline-overridable constant identifier string key 这是着色器入口点的 statically accessed:
-
如果由 key 标识的管道可覆盖常量 does not have a default value, descriptor.
constants
必须 contain key。
-
返回值 false
对应于 pipeline-creation error。
参数:
-
着色器绑定声明变量,从着色器模块反射的模块范围变量声明
-
GPUPipelineLayout
layout
让 bindGroup 是绑定组索引,和 bindIndex 是着色器绑定声明 variable 的绑定索引。
如果满足以下所有条件,则返回 true
:
-
layout.
[[bindGroupLayouts]]
[bindGroup] 包含 一个GPUBindGroupLayoutEntry
entry 其中 entry.binding
== bindIndex. -
如果对于 entry 被定义的 binding member 是:
buffer
-
"uniform"
-
variable is declared with address space
uniform
. "storage"
-
variable is declared with address space
storage
and access moderead_write
. "read-only-storage"
-
variable is declared with address space
storage
and access moderead
.
如果 entry.
buffer
.minBindingSize
不是0
,那么它必须至少是着色器中关联缓冲区变量的 minimum binding size。 如果变量具有 store type T,则最小绑定大小为 SizeOf(T)。 在这个计算中,如果 T 是一个 runtime-sized 数组或包含一个运行时大小的数组,该数组假定有一个元素。 强制执行此下限可确保通过缓冲区变量进行的读取和写入仅访问缓冲区绑定区域内的内存位置。 sampler
-
"filtering"
或者"non-filtering"
-
variable 是
sampler
类型 "comparison"
-
variable 是
comparison_sampler
类型。
texture
-
当且仅当, entry.
texture
.multisampled
是true
,变量 类型为texture_multisampled_2d<T>
或texture_depth_multisampled_2d<T>
。如果 entry.
texture
.sampleType
是:"float"
,"unfilterable-float"
,"sint"
或"uint"
-
variable 是类型
texture_1d<T>
,texture_2d<T>
,texture_2d_array<T>
,texture_cube<T>
,texture_cube_array<T>
,texture_3d<T>
, 或texture_multisampled_2d<T>
.如果 entry.
texture
.sampleType
是:"float"
or"unfilterable-float"
-
采样类型
T
是f32
. "sint"
-
采样类型
T
是i32
. "uint"
-
采样类型
T
是u32
.
"depth"
-
variable 是类型
texture_depth_2d
,texture_depth_2d_array
,texture_depth_cube
,texture_depth_cube_array
, 或texture_depth_multisampled_2d
.
如果 entry.
texture
.viewDimension
是:"1d"
-
variable 是类型
texture_1d<T>
. "2d"
-
variable 是类型
texture_2d<T>
或texture_multisampled_2d<T>
. "2d-array"
-
variable 是类型
texture_2d_array<T>
. "cube"
-
variable 是类型
texture_cube<T>
. "cube-array"
-
variable 是类型
texture_cube_array<T>
. "3d"
-
variable 是类型
texture_3d<T>
.
storageTexture
-
如果 entry.
storageTexture
.viewDimension
是:"1d"
-
variable 是类型
texture_storage_1d<T, A>
. "2d"
-
variable 是类型
texture_storage_2d<T, A>
. "2d-array"
-
variable 是类型
texture_storage_2d_array<T, A>
. "3d"
-
variable 是类型
texture_storage_3d<T, A>
.
如果 entry.
storageTexture
.access
是:"write-only"
-
访问模式“A”是“写”。
纹素格式
T
等于 entry.storageTexture
.format
.
资源绑定被视为由着色器入口点statically used 当且仅当着色器模块的控制流图可以访问它,从入口点开始。
10.2. GPUComputePipeline
GPUComputePipeline
是一种 pipeline 控制计算着色器阶段,
并且可以在 GPUComputePassEncoder
中使用。
计算输入和输出都包含在绑定中,
根据给定的 GPUPipelineLayout
。
输出对应于类型为 "storage"
的 buffer
绑定
和 storageTexture
绑定类型为 "write-only"
。
计算 pipeline 的阶段:
-
计算着色器
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUComputePipeline { };GPUComputePipeline includes GPUObjectBase ;GPUComputePipeline includes GPUPipelineBase ;
10.2.1. 创建
dictionary :
GPUComputePipelineDescriptor GPUPipelineDescriptorBase {required GPUProgrammableStage ; };
compute
createComputePipeline(descriptor)
-
创建一个
GPUComputePipeline
。调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createComputePipeline(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUComputePipelineDescriptor
✘ ✘ Description of the GPUComputePipeline
to create.-
让 pipeline 成一个新的有效的
GPUComputePipeline
对象. -
在 this 的 Device timeline 上发出以下步骤:
-
如果不满足以下任一条件:
-
descriptor.
layout
是 valid to use with this. -
validating GPUProgrammableStage(
COMPUTE
, descriptor.compute
, descriptor.layout
) 成功。 -
descriptor.
compute
使用 ≤ device.limits.maxComputeWorkgroupStorageSize
工作组存储的字节。问题:更好地定义使用静态使用等。
-
descriptor.
compute
使用 ≤ device.limits.maxComputeInvocationsPerWorkgroup
每一个工作组。 -
descriptor.
compute
的workgroup_size
属性具有每个组件 ≤ 对应的组件 [device.limits.maxComputeWorkgroupSizeX
, device.limits.maxComputeWorkgroupSizeY
, device.limits.maxComputeWorkgroupSizeZ
]。
Then:
-
在当前范围内产生一个带有适当错误信息的
GPUValidationError
。 -
使 pipeline invalid.
-
-
如果 descriptor.
layout
是undefined
:-
为 pipeline 设置 pipeline.
[[layout]]
为一个新的 default pipeline layout。
否则设置pipeline.
[[layout]]
为 descriptor.layout
。 -
-
-
返回 pipeline.
-
createComputePipelineAsync(descriptor)
-
创建一个
GPUComputePipeline
。 返回的Promise
在创建的管道准备好使用时解析,没有额外的延迟。如果管道创建失败,则返回的
Promise
会以OperationError
拒绝。注意:尽可能使用此方法,因为它可以防止阻塞管道编译中的 queue timeline 工作。
调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createComputePipelineAsync(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUComputePipelineDescriptor
✘ ✘ 要创建的 GPUComputePipeline
的描述。返回:
Promise
<GPUComputePipeline
>-
让 promise 为 a new promise.
-
在 this 的 Device timeline 上发出以下步骤:
-
让 pipeline 是一个新的
GPUComputePipeline
,就像 this 一样。createComputePipeline()
是用 descriptor 调用的; -
当 pipeline 已准备好使用,resolve promise 与pipeline。
-
-
返回 promise.
-
GPUComputePipeline
:
const computePipeline= gpuDevice. createComputePipeline({ layout: pipelineLayout, compute: { module: computeShaderModule, entryPoint: 'computeMain' , } });
10.3. GPURenderPipeline
GPURenderPipeline
是一种控制顶点和片段着色器阶段的 pipeline,
可以在 GPURenderPassEncoder
以及 GPURenderBundleEncoder
中使用。
渲染 pipeline 输入是:
-
绑定,根据给定的
GPUPipelineLayout
-
顶点和索引缓冲区,由
GPUVertexState
描述 -
颜色附件,由
GPUColorTargetState
描述 -
可选的,深度模板附件,由
GPUDepthStencilState
描述
渲染 pipeline 输出是:
-
storageTexture
与access
的"write-only"
绑定 -
颜色附件,由
GPUColorTargetState
描述 -
可选的,深度模板附件,由
GPUDepthStencilState
描述
渲染 pipeline 由以下 render stages组成:
-
顶点获取,由
GPUVertexState.buffers
控制 -
顶点着色器,由
GPUVertexState
控制 -
原始组装,由
GPUPrimitiveState
控制 -
光栅化,由
GPUPrimitiveState
、GPUDepthStencilState
和GPUMultisampleState
控制 -
片段着色器,由
GPUFragmentState
控制 -
Stencil 测试和操作,由
GPUDepthStencilState
控制 -
深度测试和写入,由
GPUDepthStencilState
控制 -
输出合并,由
GPUFragmentState.targets
控制
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPURenderPipeline { };GPURenderPipeline includes GPUObjectBase ;GPURenderPipeline includes GPUPipelineBase ;
GPURenderPipeline
有以下内部插槽:
[[descriptor]]
,GPURenderPipelineDescriptor
类型-
GPURenderPipelineDescriptor
用来描述这个管道。GPURenderPipelineDescriptor
的所有可选字段都已定义。 [[writesDepth]]
, boolean 类型-
如果管道写入深度/模板附件的深度组件,则为True
[[writesStencil]]
, boolean 类型-
如果管道写入深度/模板附件的模板组件,则为True
10.3.1. 创建
dictionary :
GPURenderPipelineDescriptor GPUPipelineDescriptorBase {required GPUVertexState ;
vertex GPUPrimitiveState = {};
primitive GPUDepthStencilState ;
depthStencil GPUMultisampleState = {};
multisample GPUFragmentState ; };
fragment
GPURenderPipelineDescriptor
通过配置每个 render stage 来描述渲染 pipeline 的状态。
有关详细信息,请参阅 § 22.3 渲染。
-
depthStencil
描述 可选的深度模板属性,包括测试、操作和偏差。 -
multisample
描述 pipeline 的多重采样特性。 -
fragment
描述 pipeline 的片段着色器入口点及其输出颜色。 如果它是null
,则启用 § 22.3.8 无颜色输出 模式。
createRenderPipeline(descriptor)
-
创建一个
GPURenderPipeline
.调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createRenderPipeline(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPURenderPipelineDescriptor
✘ ✘ Description of the GPURenderPipeline
to create.-
让 pipeline 为一个新的可用的
GPURenderPipeline
对象。 -
在 this 的 Device timeline 上发出以下步骤:
-
如果不满足以下任一条件:
-
descriptor.
layout
是 valid to use with this。 -
validating GPURenderPipelineDescriptor(descriptor, this) 成功。
Then:
-
在当前范围内产生一个带有适当错误信息的
GPUValidationError
。 -
使 pipeline invalid。
-
-
设置 pipeline.
[[descriptor]]
为 descriptor。 -
设置 pipeline.
[[writesDepth]]
为 false. -
设置 pipeline.
[[writesStencil]]
为 false. -
让 depthStencil 是 descriptor.
depthStencil
. -
如果 depthStencil 不是 null:
-
设置 pipeline.
[[writesDepth]]
为 depthStencil.depthWriteEnabled
. -
如果 depthStencil.
stencilWriteMask
不是 0:-
让 stencilFront 为 depthStencil.
stencilFront
. -
让 stencilBack 为 depthStencil.
stencilBack
. -
如果 cullMode 不是
"front"
, 并且 stencilFront.passOp
, stencilFront.depthFailOp
, 或 stencilFront.failOp
其中之一不是"keep"
:-
设置 pipeline.
[[writesStencil]]
为 true.
-
-
如果 cullMode 不是
"back"
, 并且 stencilBack.passOp
, stencilBack.depthFailOp
, 或 stencilBack.failOp
其中之一不是"keep"
:-
设置 pipeline.
[[writesStencil]]
为 true.
-
-
-
-
如果 descriptor.
layout
是undefined
:-
为 pipeline 设置 pipeline.
[[layout]]
为一个新的 default pipeline layout。
否则设置 pipeline.
[[layout]]
为 descriptor.layout
. -
-
-
返回 pipeline.
问题:需要渲染状态的描述。
-
createRenderPipelineAsync(descriptor)
-
创建一个
GPURenderPipeline
。 返回的Promise
在创建的管道准备好使用时解析,没有额外的延迟。如果管道创建失败,则返回的
Promise
会以OperationError
拒绝。注意:最好尽可能使用此方法,因为它可以防止阻塞 queue timeline 致力于管道编译。
调用:GPUDevice
this.参数:
Arguments for the GPUDevice.createRenderPipelineAsync(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPURenderPipelineDescriptor
✘ ✘ 要创建的 GPURenderPipeline
的描述。返回:
Promise
<GPURenderPipeline
>-
让 promise 为 a new promise.
-
在 this 的 device timeline 上发出以下步骤:
-
让 pipeline 是一个新创建的
GPURenderPipeline
, 就好像 this.createRenderPipeline()
是用 descriptor 调用的一样; -
当pipeline 已准备好使用, 用 pipeline resolve promise。
-
-
返回 promise.
-
-
GPURenderPipelineDescriptor
descriptor -
GPUDevice
device
如果满足以下所有条件,则返回 true
:
-
validating GPUProgrammableStage(
VERTEX
, descriptor.vertex
, descriptor.layout
) 成功。 -
validating GPUVertexState(device, descriptor.
vertex
, descriptor.vertex
) 成功。 -
如果 descriptor.
fragment
不是null
:-
validating GPUProgrammableStage(
FRAGMENT
, descriptor.fragment
, descriptor.layout
) 成功。 -
validating GPUFragmentState(descriptor.
fragment
) 成功。 -
如果 "sample_mask" builtin 是 descriptor.
fragment
的 pipeline output:-
descriptor.
multisample
.alphaToCoverageEnabled
是false
。
-
-
-
validating GPUPrimitiveState(descriptor.
primitive
, device.[[features]]
) 成功。 -
如果 descriptor.
depthStencil
不是null
:-
validating GPUDepthStencilState(descriptor.
depthStencil
) 成功。
-
-
validating GPUMultisampleState(descriptor.
multisample
) 成功。 -
对于每个用户定义的输出 descriptor.
vertex
必须有 是用户定义的输入 descriptor.fragment
即 匹配 location, 类型,和 interpolation 的输出。 -
对于每个用户定义的输入 descriptor.
fragment
在那里 必须是用户定义的输出 descriptor.vertex
即 location, 类型,和 interpolation 的输入。 -
descriptor.
vertex
的用户定义输出组件少于 device.limits.maxInterStageShaderComponents
组件。 -
descriptor.
fragment
的用户定义输入的组件少于 device.limits.maxInterStageShaderComponents
组件。
问题:我们应该验证点和线的 cullMode
是 none 吗?
问题:定义渲染目标格式的“兼容”意味着什么。
问题:需要适当限制颜色目标的最大数量。
GPURenderPipeline
:
const renderPipeline= gpuDevice. createRenderPipeline({ layout: pipelineLayout, vertex: { module: shaderModule, entryPoint: 'vertexMain' }, fragment: { module: shaderModule, entryPoint: 'fragmentMain' , targets: [{ format: 'bgra8unorm' , }], } });
10.3.2. 原始状态
enum {
GPUPrimitiveTopology ,
"point-list" ,
"line-list" ,
"line-strip" ,
"triangle-list" , };
"triangle-strip"
dictionary {
GPUPrimitiveState GPUPrimitiveTopology = "triangle-list";
topology GPUIndexFormat ;
stripIndexFormat GPUFrontFace = "ccw";
frontFace GPUCullMode = "none"; // Requires "depth-clip-control" feature.
cullMode boolean =
unclippedDepth false ; };
-
GPUPrimitiveState
descriptor -
list<
GPUFeatureName
> features
如果满足以下所有条件,则返回 true
:
-
如果 descriptor.
topology
不为"line-strip"
或"triangle-strip"
:-
descriptor.
stripIndexFormat
为undefined
-
-
如果 descriptor.
unclippedDepth
为true
:-
features 必须 contain
"depth-clip-control"
。
-
enum {
GPUFrontFace ,
"ccw" , };
"cw"
enum {
GPUCullMode ,
"none" ,
"front" , };
"back"
10.3.3. 多重采样状态
dictionary {
GPUMultisampleState GPUSize32 = 1;
count GPUSampleMask = 0xFFFFFFFF;
mask boolean =
alphaToCoverageEnabled false ; };
-
GPUMultisampleState
descriptor
如果满足以下所有条件,则返回 true
:
-
如果 descriptor.
alphaToCoverageEnabled
是true
:-
descriptor.
count
比 1 大。
-
10.3.4. 片段状态
dictionary :
GPUFragmentState GPUProgrammableStage {required sequence <GPUColorTargetState >; };
targets
true
:
-
descriptor.
targets
.length 必须 ≤ 8. -
对于每个colorState 列表中的布局描述符 descriptor.
targets
:-
colorState.
format
必须在具有RENDER_ATTACHMENT
功能的 § 25.1.1 纯色格式 中列出。 -
如果 colorState.
blend
不是undefined
:-
colorState.
format
必须是可过滤的 根据 § 25.1.1 纯色格式 表。 -
colorState.
blend
.color
必须是 valid GPUBlendComponent. -
colorState.
blend
.alpha
必须是 valid GPUBlendComponent.
-
-
colorState.
writeMask
必须是 < 16. -
如果 descriptor.
entryPoint
有一个 pipeline output 值, location 属性等于 colorState 的索引 在 descriptor.targets
列表中:-
pipeline output 类型必须与 colorState.
format
兼容。
否则:
-
colorState.
writeMask
必须为 0。
-
-
问题:定义 GPUProgrammableStage
的“静态使用”事物的范围
10.3.5. 颜色目标状态
dictionary {
GPUColorTargetState required GPUTextureFormat ;
format GPUBlendState ;
blend GPUColorWriteFlags = 0xF; // GPUColorWrite.ALL };
writeMask
dictionary {
GPUBlendState required GPUBlendComponent ;
color required GPUBlendComponent ; };
alpha
typedef [EnforceRange ]unsigned long ; [
GPUColorWriteFlags Exposed =(Window ,DedicatedWorker )]namespace {
GPUColorWrite const GPUFlagsConstant = 0x1;
RED const GPUFlagsConstant = 0x2;
GREEN const GPUFlagsConstant = 0x4;
BLUE const GPUFlagsConstant = 0x8;
ALPHA const GPUFlagsConstant = 0xF; };
ALL
10.3.5.1. 混合状态
dictionary {
GPUBlendComponent GPUBlendOperation = "add";
operation GPUBlendFactor = "one";
srcFactor GPUBlendFactor = "zero"; };
dstFactor
enum {
GPUBlendFactor ,
"zero" ,
"one" ,
"src" ,
"one-minus-src" ,
"src-alpha" ,
"one-minus-src-alpha" ,
"dst" ,
"one-minus-dst" ,
"dst-alpha" ,
"one-minus-dst-alpha" ,
"src-alpha-saturated" ,
"constant" , };
"one-minus-constant"
enum {
GPUBlendOperation ,
"add" ,
"subtract" ,
"reverse-subtract" ,
"min" , };
"max"
10.3.6. 深度/模板状态
dictionary {
GPUDepthStencilState required GPUTextureFormat ;
format boolean =
depthWriteEnabled false ;GPUCompareFunction = "always";
depthCompare GPUStencilFaceState = {};
stencilFront GPUStencilFaceState = {};
stencilBack GPUStencilValue = 0xFFFFFFFF;
stencilReadMask GPUStencilValue = 0xFFFFFFFF;
stencilWriteMask GPUDepthBias = 0;
depthBias float = 0;
depthBiasSlopeScale float = 0; };
depthBiasClamp
dictionary {
GPUStencilFaceState GPUCompareFunction = "always";
compare GPUStencilOperation = "keep";
failOp GPUStencilOperation = "keep";
depthFailOp GPUStencilOperation = "keep"; };
passOp
enum {
GPUStencilOperation ,
"keep" ,
"zero" ,
"replace" ,
"invert" ,
"increment-clamp" ,
"decrement-clamp" ,
"increment-wrap" , };
"decrement-wrap"
-
GPUDepthStencilState
descriptor
返回 true
,当且仅当满足以下所有条件:
-
descriptor.
format
为depth-or-stencil format。 -
如果 descriptor.
depthWriteEnabled
是true
或者 descriptor.depthCompare
不是"always"
:-
descriptor.
format
必须有一个深度组件。
-
-
如果 descriptor.
stencilFront
或者 descriptor.stencilBack
都不是默认值:-
descriptor.
format
必须有一个模板组件。
-
问题:该算法如何支持在扩展中添加的深度/模板格式?
10.3.7. 顶点状态
enum {
GPUIndexFormat ,
"uint16" , };
"uint32"
索引格式决定了缓冲区中索引值的数据类型,当与带状基元拓扑("line-strip"
或 "triangle-strip"
) 还指定了图元重启值。 primitive restart value 指示哪个索引值指示应该启动新的图元,而不是继续使用先前索引的顶点构造三角形条。
GPUPrimitiveState
指定条带基元拓扑必须指定 stripIndexFormat
以便在管道创建时知道将使用的 primitive restart value。
指定列表基元拓扑的 GPUPrimitiveState
必须将 stripIndexFormat
设置为 undefined
,
并且在渲染时将使用传递给 setIndexBuffer()
的索引格式。
Index format | Byte size | Primitive restart value |
---|---|---|
"uint16"
| 2 | 0xFFFF |
"uint32"
| 4 | 0xFFFFFFFF |
10.3.7.1. 顶点格式
格式的名称指定了组件的顺序、每个组件的位数、 和组件的vertex data type。
-
unorm
= unsigned normalized -
snorm
= signed normalized -
uint
= unsigned int -
sint
= signed int -
float
= floating point
enum {
GPUVertexFormat ,
"uint8x2" ,
"uint8x4" ,
"sint8x2" ,
"sint8x4" ,
"unorm8x2" ,
"unorm8x4" ,
"snorm8x2" ,
"snorm8x4" ,
"uint16x2" ,
"uint16x4" ,
"sint16x2" ,
"sint16x4" ,
"unorm16x2" ,
"unorm16x4" ,
"snorm16x2" ,
"snorm16x4" ,
"float16x2" ,
"float16x4" ,
"float32" ,
"float32x2" ,
"float32x3" ,
"float32x4" ,
"uint32" ,
"uint32x2" ,
"uint32x3" ,
"uint32x4" ,
"sint32" ,
"sint32x2" ,
"sint32x3" , };
"sint32x4"
多分量格式指定“x”后的分量数。
因此,"sint32x3"
表示着色器中 i32
值的 3 分量向量。
enum {
GPUVertexStepMode ,
"vertex" , };
"instance"
步进模式配置如何根据当前顶点或实例索引计算顶点缓冲区数据的地址:
"vertex"
-
每个顶点的地址前移
arrayStride
, 并在实例之间重置。 "instance"
-
每个实例的地址都增加了
arrayStride
。
dictionary :
GPUVertexState GPUProgrammableStage {sequence <GPUVertexBufferLayout ?>= []; };
buffers
从概念上讲,vertex buffer 是将缓冲区内存视为结构数组 的视图。 arrayStride
是该数组的 elements 之间的步幅(以字节为单位)。
顶点缓冲区的每个元素就像一个结构,其内存布局由其定义 attributes
,描述结构的成员。
每个 GPUVertexAttribute
描述了它的 format
及其 offset
,以字节为单位,在结构中。
每个属性在顶点着色器中显示为单独的输入,每个属性都由数字 location 绑定,
由 shaderLocation
指定。 GPUVertexState
中的每个位置都必须是唯一的。
dictionary {
GPUVertexBufferLayout required GPUSize64 ;
arrayStride GPUVertexStepMode = "vertex";
stepMode required sequence <GPUVertexAttribute >; };
attributes
dictionary {
GPUVertexAttribute required GPUVertexFormat ;
format required GPUSize64 ;
offset required GPUIndex32 ; };
shaderLocation
-
GPUDevice
device -
GPUVertexBufferLayout
descriptor -
GPUProgrammableStage
vertexStage
返回 true
,当且仅当满足以下所有条件:
-
descriptor.
arrayStride
≤ device.[[device]]
.[[limits]]
.maxVertexBufferArrayStride
. -
descriptor.
arrayStride
是 4 的倍数/ -
对于每个属性 attrib 在列表中 descriptor.
attributes
:-
如果 descriptor.
arrayStride
是 0:-
attrib.
offset
+ sizeof(attrib.format
) ≤ device.[[device]]
.[[limits]]
.maxVertexBufferArrayStride
.
否则:
-
attrib.
offset
+ sizeof(attrib.format
) ≤ descriptor.arrayStride
.
-
-
attrib.
shaderLocation
比 device.[[device]]
.[[limits]]
.maxVertexAttributes
小。
-
-
对于 vertexStage.
module
的着色器反射中的每个顶点属性, 即 vertexStage.entryPoint
的 pipeline input, 都有一个对应的 attrib descriptor.attributes
的元素满足以下所有条件:-
着色器格式与 attrib 兼容。
format
的 vertex data type:- "unorm", "snorm", 或 "float"
-
着色器格式必须为
f32
或vecN<f32>
。 - "uint"
-
着色器格式必须为
u32
或vecN<u32>
。 - "sint"
-
着色器格式必须为
i32
orvecN<i32>
。
-
着色器的地址为 attrib.
shaderLocation
.
-
-
GPUDevice
device -
GPUVertexState
descriptor
返回 true
,当且仅当满足以下所有条件:
-
descriptor.
buffers
.length 小于或等于 device.[[device]]
.[[limits]]
.maxVertexBuffers
. -
每个 vertexBuffer 列表中的布局描述符 descriptor.
buffers
通过 validating GPUVertexBufferLayout(device, vertexBuffer, descriptor) -
vertexBuffer.
attributes
.length 在 descriptor.buffers
中的每个 vertexBuffer 上的总和, 小于或等于 device.[[device]]
.[[limits]]
.maxVertexAttributes
。 -
每个attrib 在 descriptor.
buffers
的所有GPUVertexAttribute
的联合中,有一个不同的 attrib.shaderLocation
值。
11. 命令缓冲区
命令缓冲区是预先记录的GPU command列表,可以提交给GPUQueue
执行。每个GPU command代表一个要在GPU上执行的任务,例如设置状态、绘图、复制资源等。
11.1. GPUCommandBuffer
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUCommandBuffer { };GPUCommandBuffer includes GPUObjectBase ;
GPUCommandBuffer
有以下内部插槽:
[[command_list]]
of type list<GPU command>.-
当这个命令缓冲被提交时,一个GPU command的list会在Queue timeline上被执行。
11.1.1. 创建
dictionary :
GPUCommandBufferDescriptor GPUObjectDescriptorBase { };
12. 命令编码
12.1. GPUCommandsMixin
GPUCommandsMixin
定义了所有编码命令的接口共有的状态。它没有方法。
interface mixin GPUCommandsMixin { };
GPUCommandsMixin
将以下内部插槽添加到包含它的接口:
[[state]]
, 类型为encoder state-
编码器的当前状态,最初设置为“open”。
[[commands]]
, 类型为list<GPU command>-
当包含这些命令的
GPUCommandBuffer
被提交时,GPU commands 的 list 将在 Queue Timeline 上执行。
- "open"
-
编码器可用于对新命令进行编码。
- "locked"
-
无法使用编码器,因为它被子编码器锁定:它是一个
GPUCommandEncoder
,并且一个GPURenderPassEncoder
或GPUComputePassEncoder
处于活动状态。当传递结束时,编码器再次变为“打开”。在此状态下发出的任何命令都会使编码器invalid。
- "ended"
-
编码器已结束,无法再对新命令进行编码。
在此状态下发出的任何命令都会生成
GPUValidationError
。
GPUCommandsMixin
encoder:
如果 encoder.[[state]]
为:
- "open"
-
返回
true
. - "locked"
-
使 encoder invalid, 返回
false
. - "ended"
-
在当前范围内产生一个
GPUValidationError
,并返回false
12.2. GPUCommandEncoder
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUCommandEncoder {GPURenderPassEncoder beginRenderPass (GPURenderPassDescriptor descriptor );GPUComputePassEncoder beginComputePass (optional GPUComputePassDescriptor descriptor = {});undefined copyBufferToBuffer (GPUBuffer source ,GPUSize64 sourceOffset ,GPUBuffer destination ,GPUSize64 destinationOffset ,GPUSize64 size );undefined copyBufferToTexture (GPUImageCopyBuffer source ,GPUImageCopyTexture destination ,GPUExtent3D copySize );undefined copyTextureToBuffer (GPUImageCopyTexture source ,GPUImageCopyBuffer destination ,GPUExtent3D copySize );undefined copyTextureToTexture (GPUImageCopyTexture source ,GPUImageCopyTexture destination ,GPUExtent3D copySize );undefined clearBuffer (GPUBuffer buffer ,optional GPUSize64 offset = 0,optional GPUSize64 size );undefined writeTimestamp (GPUQuerySet querySet ,GPUSize32 queryIndex );undefined resolveQuerySet (GPUQuerySet querySet ,GPUSize32 firstQuery ,GPUSize32 queryCount ,GPUBuffer destination ,GPUSize64 destinationOffset );GPUCommandBuffer finish (optional GPUCommandBufferDescriptor descriptor = {}); };GPUCommandEncoder includes GPUObjectBase ;GPUCommandEncoder includes GPUCommandsMixin ;GPUCommandEncoder includes GPUDebugCommandsMixin ;
12.2.1. 创建
dictionary :
GPUCommandEncoderDescriptor GPUObjectDescriptorBase { };
createCommandEncoder(descriptor)
-
创建一个
GPUCommandEncoder
。Called on:GPUDevice
this.Arguments:
Arguments for the GPUDevice.createCommandEncoder(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUCommandEncoderDescriptor
✘ ✔ 要创建的 GPUCommandEncoder
的描述。Returns:
GPUCommandEncoder
问题:描述
createCommandEncoder()
算法步骤。
GPUCommandEncoder
,编码一条清理缓存的命令,结束编码器以得到 GPUCommandBuffer
,之后提交其至 GPUQueue
。
const commandEncoder= gpuDevice. createCommandEncoder(); commandEncoder. clearBuffer( buffer); const commandBuffer= commandEncoder. finish(); gpuDevice. queue. submit([ commandBuffer]);
12.3. 通道编码
beginRenderPass(descriptor)
-
Begins encoding a render pass described by descriptor.
Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.beginRenderPass(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPURenderPassDescriptor
✘ ✘ 要创建的 GPURenderPassEncoder
的描述。Returns:
GPURenderPassEncoder
在this的Device timeline上发起以下步骤:
-
使pass为一个新的
GPURenderPassEncoder
对象。 -
如果以下任何条件没有满足,产生一个校验错误并停止。
-
descriptor满足Valid Usage规则。
-
descriptor.
timestampWrites
为空,或 this.[[device]]
.[[features]]
包括(contain)"timestamp-query"
。 -
For each timestampWrite in descriptor.
timestampWrites
,-
timestampWrite.
querySet
可以与this一起有效使用(valid to use with)。
-
-
对每个descriptor.
colorAttachments
中的colorAttachment:-
colorAttachment.
view
看到的texture subresource被视为在渲染通道期间用作attachment。
-
-
设置depthStencilAttachment为descriptor.
depthStencilAttachment
。 -
如果depthStencilAttachment不是
null
:-
设置depthStencilView为depthStencilAttachment.
view
。 -
如果depthStencilAttachment.
depthReadOnly
和stencilReadOnly
设置了值:-
depthStencilView看到的texture subresource被视为在渲染通道期间用作attachment-read。
问题:用“一组子资源”算法来描述此算法。
-
-
否则, depthStencilView看到的texture subresource被视为在渲染通道期间用作attachment。
-
设置pass.
[[depthReadOnly]]
为depthStencilAttachment.depthReadOnly
。 -
设置pass.
[[stencilReadOnly]]
为depthStencilAttachment.stencilReadOnly
。
-
-
设置pass.
[[layout]]
为derive render targets layout from pass(descriptor)。 -
对每个descriptor.
timestampWrites
中的timestampWrite,-
如果timestampWrite.
location
为"beginning"
, 添加(Append)一个GPU command至pass.[[command_encoder]]
.[[commands]]
,将GPU时间戳值写入timestampWrite.querySet
的timestampWrite.queryIndex
索引处。 -
否则,timestampWrite.
location
为"end"
,添加timestampWrite至pass.[[endTimestampWrites]]
。
-
-
问题:入队附件加载/清除。
-
返回pass。
问题:指定只读深度/模板的行为。
-
beginComputePass(descriptor)
-
开始对descriptor描述的compute pass进行编码。
Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.beginComputePass(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUComputePassDescriptor
✘ ✔ Returns:
GPUComputePassEncoder
在this的Device timeline上发起如下步骤:
-
如果以下任何条件没有满足,产生一个校验错误并停止。
-
descriptor.
timestampWrites
为空,或 this.[[device]]
.[[features]]
contains"timestamp-query"
. -
对每个descriptor.
timestampWrites
中的timestampWrite,-
timestampWrite.
querySet
is valid to use with this.
-
-
设置pass为一个新的
GPUComputePassEncoder
对象。 -
对每个descriptor.
timestampWrites
中的timestampWrite,-
如果timestampWrite.
location
为"beginning"
, 添加(Append一个GPU command至pass.[[command_encoder]]
.[[commands]]
,将GPU时间戳值写入timestampWrite.querySet
中的timestampWrite.queryIndex
索引处。 index in timestampWrite.querySet
. -
否则,Otherwise, 如果timestampWrite.
location
为"end"
,则添加(Append)timestampWrite 至 pass.[[endTimestampWrites]]
。
-
-
返回pass。
-
12.4. 拷贝命令
问题:这些字典定义应该在图像副本部分内。
12.4.1. GPUImageDataLayout
dictionary GPUImageDataLayout {GPUSize64 = 0;
offset GPUSize32 bytesPerRow ;GPUSize32 rowsPerImage ; };
GPUImageDataLayout
是一些线性内存中的图像(images)布局。它在texture和buffer之间复制数据时使用,或者在调度GPUQueue
texture写入时使用。
问题:更精确地定义图像,特别地,将它们定义为由texel blocks组成。
在字节数组和纹理之间复制的操作始终适用于texel block的行,我们将其称为block row。不能只更新texel block的一部分。
Texel blocks被紧密地封装在图像副本的线性内存布局中的每个block row中,每个后续的纹素块都紧跟在前一个纹素块之后,没有填充。 这包括copying-depth-stencil到/来自depth-or-stencil format纹理的特定方面:模板值紧密地打包在字节数组中;深度值紧密地封装在适当类型(“depth16unorm”或“depth32float”)的数组中。
问题:通过参考复制方法共享的通用算法,定义精确的复制语义。
bytesPerRow
, of type GPUSize32-
每个block row的开头和后续block row之间的步幅(以字节为单位)。
如果有多个block row则为必须项(即,副本高度或深度大于一块)。
rowsPerImage
, of type GPUSize32-
每个纹理图像的block row数。
rowsPerImage
×bytesPerRow
是每个数据images的开头和后续images之间的步幅(以字节为单位)。如果有多个images则为必须项(即,副本高度大于一)。
12.4.2. GPUImageCopyBuffer
在图像复制(image copy)操作中,GPUImageCopyBuffer
定义了一个GPUBuffer
,并与 copySize
一起,定义了图像数据在缓冲区内存中如何布局(请参阅 GPUImageDataLayout)。
dictionary GPUImageCopyBuffer :GPUImageDataLayout {required GPUBuffer ; };
buffer
Arguments:
-
GPUImageCopyBuffer
imageCopyBuffer
Returns: boolean
当且仅当所有以下条件都满足时,返回 true
。
-
imageCopyBuffer.
bytesPerRow
必须是256的倍数。
12.4.3. GPUImageCopyTexture
在图像复制(image copy)操作中,GPUImageCopyTexture
定义了一个GPUTexture
,并与 copySize
一起定义了纹理的子区域(跨越相同 mip-map 级别的一个或多个连续texture subresource)。
dictionary GPUImageCopyTexture {required GPUTexture texture ;GPUIntegerCoordinate mipLevel = 0;GPUOrigin3D origin = {};GPUTextureAspect aspect = "all"; };
texture
, of type GPUTexture-
要复制到/从的纹理。
mipLevel
, of type GPUIntegerCoordinate, defaulting to0
-
要复制到/从的
texture
的Mip-map级别。 origin
, of type GPUOrigin3D, defaulting to{}
-
定义复制的原点 - 要复制到/从的纹理子区域的最小角。与
copySize
一起定义完整复制子区域。 aspect
, of type GPUTextureAspect, defaulting to"all"
-
定义要复制到/从纹理的宽高比。
Arguments:
-
GPUImageCopyTexture
imageCopyTexture -
GPUExtent3D
copySize
Returns: boolean
使:
-
blockWidth为imageCopyTexture.
texture
.[[descriptor]]
.format
的texel block width。 -
blockHeight为imageCopyTexture.
texture
.[[descriptor]]
.format
的texel block height。
当且仅当以下所有条件都满足时,返回 true
:
-
imageCopyTexture.
texture
必须为一个validGPUTexture
. -
imageCopyTexture.
mipLevel
必须小于imageCopyTexture.texture
的[[descriptor]]
.mipLevelCount
。 -
如果满足以下任一条件,则imageCopyTexture的imageCopyTexture subresource size等于copySize:
-
imageCopyTexture.
texture
.[[descriptor]]
.format
是一个depth-stencil格式。 -
imageCopyTexture.
texture
.[[descriptor]]
.sampleCount
大于1。
-
问题(gpuweb/gpuweb#69):使用1d
和3d
纹理定义副本。
12.4.4. GPUImageCopyTextureTagged
WebGPU纹理保存原始数字数据,并且没有用描述颜色的语义元数据标记。 但是,copyExternalImageToTexture()
从描述颜色的来源进行复制。
一个GPUImageCopyTextureTagged
是一个GPUImageCopyTexture
,它额外标记了颜色空间/编码和alpha预乘元数据,以便可以在复制期间保留语义颜色数据。
此元数据仅影响copyExternalImageToTexture()
操作的语义,而不是目标纹理的语义。
dictionary GPUImageCopyTextureTagged :GPUImageCopyTexture {GPUPredefinedColorSpace colorSpace = "srgb";boolean premultipliedAlpha =false ; };
colorSpace
, of type GPUPredefinedColorSpace, defaulting to"srgb"
-
描述用于将数据编码到目标纹理中的颜色空间和编码。
此may result在范围[0, 1]之外的值被写入目标纹理,如果它的格式可以表示它们。否则,结果将被限制在目标纹理格式的范围内。
Note: 注意:如果
colorSpace
与源图像匹配,则不会发生转换。ImageBitmap
颜色空间标记和转换可以通过ImageBitmapOptions
进行控制。 premultipliedAlpha
, of type boolean, defaulting tofalse
-
描述写入纹理的数据是否应将其RGB通道预乘以Alpha通道。
如果此选项设置为
true
并且source
也预乘,则即使源RGB值超过其相应的alpha值,也必须保留它们。注意:如果
premultipliedAlpha
与源图像匹配,则不会发生转换。2d画布总是被预乘,而WebGL画布可以通过WebGLContextAttributes控制。ImageBitmap
预乘可以通过ImageBitmapOptions
控制。
问题:将颜色值的编码定义(并测试)为copyExternalImageToTexture()
允许的各种编码。
12.4.5. GPUImageCopyExternalImage
dictionary GPUImageCopyExternalImage {required (ImageBitmap or HTMLCanvasElement or OffscreenCanvas )source ;GPUOrigin2D origin = {};boolean flipY =false ; };
GPUImageCopyExternalImage
有以下成员:
source
, of type(ImageBitmap or HTMLCanvasElement or OffscreenCanvas)
-
图像副本(image copy)的来源。源数据副本在发出
copyExternalImageToTexture()
时被捕获。 origin
, of type GPUOrigin2D, defaulting to{}
-
定义副本的原点 - 要从中复制的源子区域的最小(top-left)角。与
copySize
一起定义完整子区域副本。 flipY
, of type boolean, defaulting tofalse
-
描述源图像是否垂直翻转。
如果此选项设置为
true
,则垂直翻转副本:源区域的底行被复制到目标区域的第一行,依此类推。origin
选项仍然相对于源图像的左上角,向下增加。
12.4.6. 缓冲区副本
copyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size)
-
将命令编码到
GPUCommandEncoder
中,将数据从GPUBuffer
的子区域复制到另一个GPUBuffer
的子区域。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.copyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size) method. Parameter Type Nullable Optional Description source
GPUBuffer
✘ ✘ 要复制的 GPUBuffer
.sourceOffset
GPUSize64
✘ ✘ 到要复制的source中的字节偏移量。 destination
GPUBuffer
✘ ✘ 要复制到的 GPUBuffer
.destinationOffset
GPUSize64
✘ ✘ 到要复制到的的destination中的字节偏移量。 size
GPUSize64
✘ ✘ 要复制的字节大小。 Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态(Prepare the encoder state)。如果返回 false,则停止。
-
如果不满足以下任何条件,则产生一个校验错误并停止。
-
source可以和this一起有效使用。
-
destination可以和this一起有效使用。
-
size是4的倍数。
-
sourceOffset是4的倍数。
-
destinationOffset是4的倍数。
-
(sourceOffset + size)不会溢出
GPUSize64
。 -
(destinationOffset + size)不会溢出
GPUSize64
。 -
source.
[[size]]
大于等于(sourceOffset + size)。 -
destination.
[[size]]
大于等于(destinationOffset + size)。 -
source和destination不是同一个
GPUBuffer
。
问题(gpuweb/gpuweb#69):指出如何处理规范中的溢出。
-
问题:描述 GPU 命令并将其排入队列。
-
12.4.7. 缓冲区填充
clearBuffer(buffer, offset, size)
-
将命令编码到
GPUCommandEncoder
中,用零填充GPUBuffer
的子区域。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.clearBuffer(buffer, offset, size) method. Parameter Type Nullable Optional Description buffer
GPUBuffer
✘ ✘ 将要清除的 GPUBuffer
。offset
GPUSize64
✘ ✔ 以字节为单位的偏移量到buffer要清除的子区域开始的地方。 size
GPUSize64
✘ ✔ 要清除的子区域的大小(以字节为单位)。 默认为缓冲区的大小减去 offset。 Returns:
undefined
在this.
[[device]]
的Device timeline上发起以下步骤:-
准备this的编码器状态(Prepare the encoder state)。如果返回 false,则停止。
-
如果size缺失, 设置size为
max(0, |buffer|.{{GPUBuffer/[[size]]}} - |offset|)
。 -
如果以下任何条件未满足,生成一个校验错误并停止。
-
buffer可以和this一起有效使用(valid to use with)。
-
size为4的倍数。
-
offset为4的倍数。
-
buffer.
[[size]]
大于或等于(offset + size)。
-
-
12.4.8. Image Copies
WebGPU提供copyBufferToTexture()
以buffer-to-texture拷贝,copyTextureToBuffer()
以texture-to-buffer拷贝,以及writeTexture()
以ArrayBuffer-to-texture写入。
以下定义和校验规则对这些方法以及copyTextureToTexture()
都应用。
问题:术语“图像拷贝”包括copyTextureToTexture么?
imageCopyTexture subresource size和valid texture copy range同样对 copyTextureToTexture()
应用。
imageCopyTexture subresource size
Arguments:
-
GPUImageCopyTexture
imageCopyTexture
Returns: GPUExtent3D
imageCopyTexture的imageCopyTexture subresource size计算如下:
它的width, height和depthOrArrayLayers分别为=mipmap level=] imageCopyTexture.mipLevel
上的imageCopyTexture.texture
subresource physical size的宽度,高度,和深度。
问题:将此定义为具有 (texture, mipmapLevel) 参数的算法,并使用调用语法而不是通过标签引用定义。
Arguments:
GPUImageDataLayout
layout-
线性纹理数据的布局。
GPUSize64
byteSize-
显性数据的总大小,以字节为单位。
GPUTextureFormat
format-
纹理格式。
GPUExtent3D
copyExtent-
要复制的纹理的范围。
-
使blockWidth, blockHeight, and blockSize为格式的texel block width,height,和size。
-
假设copyExtent.width为blockWidth的倍数并且copyExtent.height为blockHeight的倍数。使:
-
如果以下条件未满足则失败:
-
如果heightInBlocks > 1,layout.
bytesPerRow
需要被指定。 -
如果copyExtent.depthOrArrayLayers > 1, layout.
bytesPerRow
和layout.rowsPerImage
需要被指定。 -
如果被指定,layout.
bytesPerRow
必须大于或等于bytesInLastRow。 -
如果被指定,layout.
rowsPerImage
必须大于或等于heightInBlocks。
-
-
使requiredBytesInCopy为0。
-
如果copyExtent|.depthOrArrayLayers > 1:
-
使bytesPerImage为 layout.
bytesPerRow
× layout.rowsPerImage
。 -
使bytesBeforeLastImage为 bytesPerImage × (copyExtent.depthOrArrayLayers − 1)。
-
将bytesBeforeLastImage加至requiredBytesInCopy。
-
-
如果copyExtent.depthOrArrayLayers > 0:
-
如果heightInBlocks > 1, 将 layout.
bytesPerRow
× (heightInBlocks − 1) 加至requiredBytesInCopy。 -
如果heightInBlocks > 0, 将 bytesInLastRow加至requiredBytesInCopy。
-
-
如果以下条件未满足则失败:
-
layout.
offset
+ requiredBytesInCopy ≤ byteSize。
-
给定一个 GPUImageCopyTexture
imageCopyTexture 和一个 GPUExtent3D
copySize, 使
-
blockWidth 为 imageCopyTexture.
texture
.[[descriptor]]
.format
的 texel block width. -
blockHeight 为 imageCopyTexture.
texture
.[[descriptor]]
.format
的 texel block height.
应用以下校验:
-
如果 imageCopyTexture.
texture
的[[descriptor]]
.dimension
为1d
:-
copySize.height 与 depthOrArrayLayers 都必须为 1.
-
-
如果 imageCopyTexture.
texture
的[[descriptor]]
.dimension
为2d
:-
(imageCopyTexture.
origin
.x + copySize.width), (imageCopyTexture.origin
.y + copySize.height), 且 (imageCopyTexture.origin
.z + copySize.depthOrArrayLayers) 必须分别地小于或等于imageCopyTexture的imageCopyTexture subresource size的 width, height, 和 depthOrArrayLayers。 -
copySize.width必须为blockWidth的倍数。
-
copySize.height必须为blockHeight的倍数。
-
问题(gpuweb/gpuweb#69): 使用 1d
和 3d
纹理定义副本
问题(gpuweb/gpuweb#537):对rowsPerImage附加的限制,如果需要。
问题(gpuweb/gpuweb#652): 定义"depth24plus"
, "depth24plus-stencil8"
, 和"stencil8"
的副本。
问题: 将“有效纹理副本范围”转换为一个带有参数的算法,与“验证线性纹理数据”相似。
copyBufferToTexture(source, destination, copySize)
-
将命令编码到
GPUCommandEncoder
中,将数据从GPUBuffer
的子区域复制到一个或多个连续texture subresource的子区域。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.copyBufferToTexture(source, destination, copySize) method. Parameter Type Nullable Optional Description source
GPUImageCopyBuffer
✘ ✘ 结合copySize,定义源缓冲区的区域。 destination
GPUImageCopyTexture
✘ ✘ 结合复制大小,定义目标texture subresource的区域。 copySize
GPUExtent3D
✘ ✘ Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态(Prepare the encoder state。如果返回 false,则停止。
-
如果以下任何条件未满足,则生成一个校验错误并停止。
-
使dstTextureDesc为destination.
texture
.[[descriptor]]
。 -
validating GPUImageCopyBuffer(source)返回
true
。 -
validating GPUImageCopyTexture(destination, copySize)返回
true
。 -
dstTextureDesc.
sampleCount
为1。 -
如果dstTextureDesc.
format
为depth-or-stencil format:-
destination.
aspect
必须指向一个dstTextureDesc.format
的单个宽高比。并且该宽高比必须为一个按照§ 25.1.2 深度-模板格式的有效图片副本目标。
-
-
如果dstTextureDesc.
format
不是depth-or-stencil format:-
source.
offset
为dstTextureDesc.format
的texel block size的倍数。
-
-
如果dstTextureDesc.
format
是depth-or-stencil format:-
source.
offset
为4的倍数。
-
-
validating linear texture data(source, source.
buffer
.[[size]]
, dstTextureDesc.format
, copySize)成功。
-
-
copyTextureToBuffer(source, destination, copySize)
-
将命令编码到
GPUCommandEncoder
中,将数据从一个或多个连续texture subresource的子区域复制到GPUBuffer
的子区域。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.copyTextureToBuffer(source, destination, copySize) method. Parameter Type Nullable Optional Description source
GPUImageCopyTexture
✘ ✘ 结合copySize,定义源texture subresource的区域。 destination
GPUImageCopyBuffer
✘ ✘ 结合copySize,定义目标缓冲区的区域。 copySize
GPUExtent3D
✘ ✘ Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态。如果返回false,则停止。
-
如果以下任何条件未满足,产生一个校验错误并停止。
-
Let srcTextureDesc为source.
texture
.[[descriptor]]
。 -
validating GPUImageCopyTexture(source, copySize)返回
true
。 -
srcTextureDesc.
sampleCount
为1。 -
如果srcTextureDesc.
format
为depth-stencil格式:-
destination.
aspect
必须指向一个srcTextureDesc.format
的单个宽高比,并且此宽高比必须为一个按照§ 25.1.2 深度-模板格式有效的图像拷贝源。
-
-
validating GPUImageCopyBuffer(destination)返回
true
。 -
Valid Texture Copy Range应用至destination和copySize。
-
如果srcTextureDesc.
format
不是depth-or-stencil format:-
destination.
offset
srcTextureDesc.format
的texel block size的倍数。
-
-
如果srcTextureDesc.
format
是depth-or-stencil format:-
destination.
offset
是4的倍数。
-
-
validating linear texture data(destination, destination.
buffer
.[[size]]
, srcTextureDesc.format
, copySize)成功。
-
-
copyTextureToTexture(source, destination, copySize)
-
将命令编码到
GPUCommandEncoder
中,该命令将数据从一个或多个连续texture subresource的子区域复制到一个或多个连续texture subresource的另一个子区域。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.copyTextureToTexture(source, destination, copySize) method. Parameter Type Nullable Optional Description source
GPUImageCopyTexture
✘ ✘ 结合copySize,定义源texture subresource的区域。 destination
GPUImageCopyTexture
✘ ✘ 结合copySize,定义目标texture subresource的区域。 copySize
GPUExtent3D
✘ ✘ Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态。如果返回 false,则停止。
-
如果以下任何条件未满足,生成一个校验错误并停止。
-
使srcTextureDesc为source.
texture
.[[descriptor]]
。 -
使dstTextureDesc为destination.
texture
.[[descriptor]]
。 -
validating GPUImageCopyTexture(source, copySize)返回
true
。 -
validating GPUImageCopyTexture(destination, copySize)返回
true
。 -
srcTextureDesc.
sampleCount
等于dstTextureDesc.sampleCount
。 -
srcTextureDesc.
format
和dstTextureDesc.format
必须为copy-compatible。 -
如果srcTextureDesc.
format
是depth-stencil格式: -
Valid Texture Copy Range(source, copySize)为真.
-
Valid Texture Copy Range(destination, copySize)为真.
-
set of subresources for texture copy(source, copySize)和set of subresources for texture copy(destination, copySize)是不相交的。
-
-
GPUTextureFormat
s format1 and format2 are copy-compatible if:
-
format1 equals format2, or
-
format1 and format2 differ only in whether they are
srgb
formats (have the-srgb
suffix).
问题(gpuweb/gpuweb#2322): 一旦 viewFormats
中允许更多格式,考虑在 viewFormats 中有任何重叠时使两个纹理副本兼容.
-
如果imageCopyTexture.
texture
.[[descriptor]]
.dimension
为"2d"
:-
每个copySize.depthOrArrayLayers array layers的arrayLayer从imageCopyTexture.
origin
.z开始:-
imageCopyTexture.
texture
的The subresource在mipmap level imageCopyTexture.mipLevel
和array layer arrayLayer处。
-
-
-
否则:
-
imageCopyTexture.
texture
的subresource在mipmap level imageCopyTexture.mipLevel
处。
-
12.5. 查询
writeTimestamp(querySet, queryIndex)
-
当所有先前命令被全部执行时,向查询集中写入一个时间戳值。
Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.writeTimestamp(querySet, queryIndex) method. Parameter Type Nullable Optional Description querySet
GPUQuerySet
✘ ✘ 存放时间戳的查询集合。 queryIndex
GPUSize32
✘ ✘ 查询集合的查询索引。 Returns:
undefined
-
如果this.
[[device]]
.[[features]]
不为contain"timestamp-query"
,抛出一个TypeError
。 -
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态。如果返回 false,则停止。
-
如果以下任何条件未满足,生成一个校验错误并停止。
-
querySet可以与this一起有效使用。
-
querySet.
[[descriptor]]
.type
为"timestamp"
。 -
queryIndex < querySet.
[[descriptor]]
.count
。
问题: 描述
writeTimestamp()
算法步骤。 -
-
resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset)
-
将来自
GPUQuerySet
的查询结果解析为GPUBuffer
的范围。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset) method. Parameter Type Nullable Optional Description querySet
GPUQuerySet
✘ ✘ firstQuery
GPUSize32
✘ ✘ queryCount
GPUSize32
✘ ✘ destination
GPUBuffer
✘ ✘ destinationOffset
GPUSize64
✘ ✘ Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态。如果返回 false,则停止。
-
如果以下任何条件未满足,生成一个
GPUValidationError
并停止。-
querySet为valid to use with this。
-
destination为valid to use with this。
-
destination.
[[usage]]
包含QUERY_RESOLVE
。 -
firstQuery小于querySet中的查询数量。
-
(firstQuery + queryCount)小于等于querySet中的查询数量。
-
destinationOffset是256的倍数。
-
destinationOffset + 8 × queryCount ≤ destination.
[[size]]
。
问题: 描述
resolveQuerySet()
算法步骤。
-
12.6. 结尾
可以通过调用finish()
来创建包含GPUCommandEncoder
记录的命令的GPUCommandBuffer
。 一旦finish()
被调用,命令编码器就不能再使用了。
finish(descriptor)
-
停止记录命令序列并返回一个对应的
GPUCommandBuffer
。Called on:GPUCommandEncoder
this.Arguments:
Arguments for the GPUCommandEncoder.finish(descriptor) method. Parameter Type Nullable Optional Description descriptor
GPUCommandBufferDescriptor
✘ ✔ Returns:
GPUCommandBuffer
-
使commandBuffer为一个新的
GPUCommandBuffer
。 -
在this的Device timeline上发起如下步骤:
-
如果以下条件都满足则使 validationFailed 为
true
,否则为false
。-
this必须为valid.
-
this.
[[debug_group_stack]]
必须为be empty。 -
每个包含在this中的usage scope必须满足usage scope validation。
-
-
如果 validationFailed 为
false
, 则:-
在当前范围内生成一个带有适当错误消息的
GPUValidationError
。 -
返回一个新的invalid
GPUCommandBuffer
。
-
-
设置commandBuffer.
[[command_list]]
为this.[[commands]]
。
-
-
返回commandBuffer。
-
13. Programmable Passes
interface mixin {
GPUProgrammablePassEncoder undefined setBindGroup (GPUIndex32 index ,GPUBindGroup bindGroup ,optional sequence <GPUBufferDynamicOffset >= []);
dynamicOffsets undefined setBindGroup (GPUIndex32 index ,GPUBindGroup bindGroup ,Uint32Array dynamicOffsetsData ,GPUSize64 dynamicOffsetsDataStart ,GPUSize32 dynamicOffsetsDataLength ); };
GPUProgrammablePassEncoder
has the following internal slots:
[[command_encoder]]
of typeGPUCommandEncoder
.-
The
GPUCommandEncoder
that created this programmable pass. [[bind_groups]]
, of type ordered map<GPUIndex32
,GPUBindGroup
>-
The current
GPUBindGroup
for each index, initially empty.
13.1. 绑定组
setBindGroup(index, bindGroup, dynamicOffsets)
-
为给定索引设置当前
GPUBindGroup
。调用:GPUProgrammablePassEncoder
this.参数:
Arguments for the GPUProgrammablePassEncoder.setBindGroup(index, bindGroup, dynamicOffsets) method. Parameter Type Nullable Optional Description index
GPUIndex32
✘ ✘ 设置绑定组的索引。 bindGroup
GPUBindGroup
✘ ✘ 绑定组以用于后续渲染或计算命令。 返回:
undefined
在 this.
[[device]]
的 Device timeline 发布一下步骤 :-
如果不满足以下任一条件,则使 this invalid 并停止。
-
bindGroup 与this 一起使用是有效的。
-
index < this.
[[device]]
.[[limits]]
.maxBindGroups
. -
dynamicOffsets.length 是 bindGroup.
[[layout]]
.[[dynamicOffsetCount]]
. -
迭代 bindGroup 中的每个动态绑定偏移量 并为每个 bufferBinding、bufferLayout 和 dynamicOffsetIndex 运行以下步骤:
-
让 bufferDynamicOffset 为 dynamicOffsets[dynamicOffsetIndex].
-
bufferBinding.
offset
+ bufferDynamicOffset + bufferLayout.minBindingSize
≤ bufferBinding.buffer
.[[size]]
. -
如果 bufferLayout.
type
是"uniform"
:-
dynamicOffset 是
minUniformBufferOffsetAlignment
的倍数。
-
-
如果 bufferLayout.
type
是"storage"
或"read-only-storage"
:-
dynamicOffset 是
minStorageBufferOffsetAlignment
的倍数。
-
-
-
-
设置 this.
[[bind_groups]]
[index 为 bindGroup.
-
setBindGroup(index, bindGroup, dynamicOffsetsData, dynamicOffsetsDataStart, dynamicOffsetsDataLength)
-
为给定索引设置当前
GPUBindGroup
,将动态偏移指定为Uint32Array
的子集。调用:GPUProgrammablePassEncoder
this.参数:
Arguments for the GPUProgrammablePassEncoder.setBindGroup(index, bindGroup, dynamicOffsetsData, dynamicOffsetsDataStart, dynamicOffsetsDataLength) method. Parameter Type Nullable Optional Description index
GPUIndex32
✘ ✘ 设置绑定组的索引。 bindGroup
GPUBindGroup
✘ ✘ 绑定组以用于后续渲染或计算命令。 dynamicOffsetsData
Uint32Array
✘ ✘ 包含 bindGroup 中每个条目的缓冲区偏移量(以字节为单位)的数组 标记为 buffer
.hasDynamicOffset
。dynamicOffsetsDataStart
GPUSize64
✘ ✘ 将元素偏移到 dynamicOffsetsData 缓冲区偏移数据开始的地方。 dynamicOffsetsDataLength
GPUSize32
✘ ✘ 要从 dynamicOffsetsData 读取的缓冲区偏移量数。 返回:
undefined
-
如果未满足以下任何要求,则抛出
RangeError
并停止。-
dynamicOffsetsDataStart 必须 ≥ 0.
-
dynamicOffsetsDataStart + dynamicOffsetsDataLength 必须 ≤ dynamicOffsetsData.
length
.
-
-
让 dynamicOffsets 成为一个 list 包含一个范围, 从获取缓冲区源的副本dynamicOffsetsData 的元素 dynamicOffsetsDataLength 的索引 dynamicOffsetsDataStart 开始。
-
调用 this.
setBindGroup
(index, bindGroup, dynamicOffsets)。
-
GPUBindGroup
中的每个动态绑定偏移 bindGroup 使用给定的 steps 为每个动态偏移执行:
-
让 dynamicOffsetIndex 为
0
。 -
让 layout 为 bindGroup.
[[layout]]
。 -
对于每个 bindGroup.
[[entries]]
中的GPUBindGroupEntry
entry:-
让 bindingDescriptor 成为
GPUBindGroupLayoutEntry
在 layout.[[entryMap]]
[entry.binding
]: -
如果 bindingDescriptor.
buffer
不是undefined
并且 bindingDescriptor.buffer
.hasDynamicOffset
是true
:
-
参数:
GPUProgrammablePassEncoder
encoder-
正在验证绑定组的编码器。
GPUPipelineBase
pipeline-
用于验证 encoders 绑定组是否兼容的管道。
-
如果不满足以下任何一个条件,则返回
false
:-
pipeline 不可以是
null
。 -
必须设置管线使用的所有绑定组并与管线布局兼容: 对于在pipeline.
[[layout]]
.[[bindGroupLayouts]]
(GPUIndex32
中的每一对 index,GPUBindGroupLayout
bindGroupLayout) 。-
让 bindGroup 为 encoder.
[[bind_groups]]
[index]. -
bindGroup 不可以是
null
。 -
bindGroup.
[[layout]]
必须是与 bindGroupLayout group-equivalent。
-
问题:对未使用
minBindingSize
预先验证的缓冲区绑定添加验证,绑定范围足以满足着色器的最小绑定大小要求。 -
-
Encoder bind groups alias a writable resource(encoder, pipeline) 必须为
false
.问题(gpuweb/gpuweb#1842): 确定当应用程序违反此规则时会发生什么。 它是验证错误,多种可能行为之一,还是我们只是完全删除此限制并允许可写绑定以未定义结果为别名?
否则返回 true
。
GPUTextureView
对象)重叠), Encoder bind groups alias a writable resource(encoder, pipeline)。
Arguments:
GPUProgrammablePassEncoder
encoder-
Encoder whose bind groups are being validated.
GPUPipelineBase
pipeline-
Pipeline to validate encoders bind groups are compatible with.
-
对每个 [
VERTEX
,FRAGMENT
,COMPUTE
] 中的 stage:-
使 bufferBindings 为 (
GPUBufferBinding
中的 list,boolean
) 对,其中后者指资源是否可写入。 -
对每个 pipeline.
[[layout]]
.[[bindGroupLayouts]]
中的 (GPUIndex32
index,GPUBindGroupLayout
bindGroupLayout) 对:-
使 bindGroupEntries 为 encoder.
[[bind_groups]]
[index].entries
. -
使 bindGroupLayoutEntries 为 bindGroupLayout.
[[descriptor]]
.entries
. -
对每个 bindGroupLayoutEntries 中的
GPUBindGroupEntry
bindGroupLayoutEntry: 对包含 stage 的 bindGroupLayoutEntry.visibility
:-
使 bindGroupEntry 为 bindGroupEntries 中的
GPUBindGroupEntry
,其 bindGroupEntry.binding
等于 bindGroupLayoutEntry.binding
。 -
如果 bindGroupEntry.
resource
为GPUBufferBinding
:-
使
GPUBufferBinding
resource 为 bindGroupEntry.resource
. -
使 resourceWritable 为 (bindGroupLayoutEntry.
buffer
.type
=="storage"
). -
对每个 bufferBindings 中的 (
GPUBufferBinding
pastResource,boolean
pastResourceWritable) 对:-
如果 (resourceWritable or pastResourceWritable) 为真, 及 pastResource 和 resource 为 buffer-binding-aliasing, 返回
true
.
-
-
Append ([resource], resourceWritable) 至 bufferBindings.
否则,如果 bindGroupEntry.
resource
为GPUTextureView
:-
使
GPUTextureView
resource 为 bindGroupEntry.resource
. -
使 resourceWritable 为 (bindGroupLayoutEntry.
storageTexture
.access
=="write-only"
). -
如果 bindGroupLayoutEntry.
storageTexture
为null
, 则继续. -
对每个 textureViews 中的 (
GPUTextureView
pastResource,boolean
pastResourceWritable) 对,-
如果 (resourceWritable or pastResourceWritable) 为真, 及 pastResource 和 resource 为 texture-view-aliasing, 返回
true
.
-
-
Append ([resource], resourceWritable) 至 textureViews.
否则,继续。
-
-
-
-
-
Return
false
.
14. 调试标记
GPUDebugCommandsMixin
提供了将调试标签应用于命令组或将单个标签插入命令序列的方法。
调试组可以嵌套以创建标记命令的层次结构,并且必须很好地平衡。
与 object labels
一样,这些标签没有必需的行为,但可能会显示在错误消息和浏览器开发人员工具中,并且可能会传递给原生 API 后端。
interface mixin GPUDebugCommandsMixin {undefined pushDebugGroup (USVString groupLabel );undefined popDebugGroup ();undefined insertDebugMarker (USVString markerLabel ); };
GPUDebugCommandsMixin
仅包含在包含 GPUObjectBase
和 GPUCommandsMixin
的接口中。
GPUDebugCommandsMixin
将以下内部插槽添加到包含它的接口中:
[[debug_group_stack]]
of type stack<USVString
>.-
一个活动调试组标签组成的堆。
GPUDebugCommandsMixin
adds the following methods to interfaces which include it:
pushDebugGroup(groupLabel)
-
开始包含后续命令的标记调试组。
Called on:GPUDebugCommandsMixin
this.Arguments:
Arguments for the GPUDebugCommandsMixin.pushDebugGroup(groupLabel) method. Parameter Type Nullable Optional Description groupLabel
USVString
✘ ✘ 命令组的标签。 Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态(Prepare the encoder state)。如果返回false,则停止。
-
在this.
[[debug_group_stack]]
上Push groupLabel。
-
popDebugGroup()
-
结束最近由
pushDebugGroup()
启动的标记调试组。Called on:GPUDebugCommandsMixin
this.Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态(Prepare the encoder state)。如果为false,则停止。
-
如果不满足以下任何要求,则使 this 无效,然后停止。
-
this.
[[debug_group_stack]]
必须不为 be empty.
-
-
从 this.
[[debug_group_stack]]
中 Pop 出一项。
-
insertDebugMarker(markerLabel)
-
用标签标记命令流中的一个点。
Called on:GPUDebugCommandsMixin
this.Arguments:
Arguments for the GPUDebugCommandsMixin.insertDebugMarker(markerLabel) method. Parameter Type Nullable Optional Description markerLabel
USVString
✘ ✘ 要插入的标签。 Returns:
undefined
在 this.
[[device]]
的 Device Timeline 上发出以下步骤:-
准备this的编码器状态(Prepare the encoder state)。如果为false,则停止。
-
15. 计算通道
15.1. GPUComputePassEncoder
[Exposed =(Window ,DedicatedWorker ),SecureContext ]interface GPUComputePassEncoder {undefined setPipeline (GPUComputePipeline pipeline );undefined dispatch (GPUSize32 workgroupCountX ,optional GPUSize32 workgroupCountY = 1,optional GPUSize32 workgroupCountZ = 1);undefined dispatchIndirect (GPUBuffer indirectBuffer ,GPUSize64 indirectOffset );undefined endPass (); };GPUComputePassEncoder includes GPUObjectBase ;GPUComputePassEncoder includes GPUProgrammablePassEncoder ;
GPUComputePassEncoder
有以下内部插槽:
[[pipeline]]
, of typeGPUComputePipeline
-
当前
GPUComputePipeline
,初始为null
。 [[endTimestampWrites]]
, of typeGPUComputePassTimestampWrites
-
通道结束时需要被执行的时间戳附件。
15.1.1. 创建
enum {
GPUComputePassTimestampLocation ,
"beginning" , };
"end" dictionary {
GPUComputePassTimestampWrite required GPUQuerySet ;
querySet required GPUSize32 ;
queryIndex required GPUComputePassTimestampLocation ; };
location typedef sequence <GPUComputePassTimestampWrite >;
GPUComputePassTimestampWrites dictionary :
GPUComputePassDescriptor GPUObjectDescriptorBase {GPUComputePassTimestampWrites timestampWrites = []; };
timestampWrites
, of type GPUComputePassTimestampWrites, defaulting to[]
-
A sequence of
GPUComputePassTimestampWrite
values define where and when timestamp values will be written for this pass.
Given a GPUComputePassDescriptor
this the following validation rules apply:
-
For each timestampWrite in this.
timestampWrites
:-
timestampWrite.
querySet
.[[descriptor]]
.type
is"timestamp"
. -
timestampWrite.
queryIndex
< timestampWrite.querySet
.[[descriptor]]
.count
.
-
15.1.2. 调度
setPipeline(pipeline)
-
设置当前
GPUComputePipeline
。Called on:GPUComputePassEncoder
this.Arguments:
Arguments for the GPUComputePassEncoder.setPipeline(pipeline) method. Parameter Type Nullable Optional Description pipeline
GPUComputePipeline
✘ ✘ 用于后续调度命令的计算管道。 Returns:
undefined
在this.
[[device]]
的Device timeline上发起以下步骤:-
如果以下任何条件未满足,使this invalid并且停止。
-
pipeline可以和this一起有效使用。
-
-
设置this.
[[pipeline]]
为pipeline。
-
dispatch(workgroupCountX, workgroupCountY, workgroupCountZ)
-
使用当前
GPUComputePipeline
执行的调度工作。有关详细规范,请参阅§ 22.2 计算。Called on:GPUComputePassEncoder
this.Arguments:
Arguments for the GPUComputePassEncoder.dispatch(workgroupCountX, workgroupCountY, workgroupCountZ) method. Parameter Type Nullable Optional Description workgroupCountX
GPUSize32
✘ ✘ 要调度的工作组网格的X维度。 workgroupCountY
GPUSize32
✘ ✔ 要调度的工作组网格的Y维度。 workgroupCountZ
GPUSize32
✘ ✔ 要调度的工作组网格的Z维度。 Returns:
undefined
在this.
[[device]]
的Device timeline上发起以下步骤:-
如果以下任何条件未满足,使this invalid并停止。
-
Validate encoder bind groups(this, this.
[[pipeline]]
)为true
。 -
workgroupCountX,workgroupCountY,和workgroupCountZ都小于或等于this.device.limits.
maxComputeWorkgroupsPerDimension
。
-
-
使passState为一个this|的快照当前状态。
-
Append 一个 GPU command 至 this.
[[commands]]
,执行以下 queue timeline 步骤:-
使用 passState 调度维度为 [workgroupCountX, workgroupCountY, workgroupCountZ] 的工作组网格。
[[pipeline]]
使用 passState.[[bind_groups]]
。
-
-
dispatchIndirect(indirectBuffer, indirectOffset)
-
使用从
GPUBuffer
读取的参数调度要与当前{{GPUComputePipeline}一起执行的工作。有关详细规范,请参阅§ 22.2 计算。缓冲区中indirect dispatch parameters必须是三个32位无符号整数值(共12个字节)的紧密打包块,以与
dispatch()
的参数相同的顺序给出。例如:let dispatchIndirectParameters= new Uint32Array( 3 ); dispatchIndirectParameters[ 0 ]