WebGPU

Editor’s Draft,

More details about this document
This version:
https://gpuweb.github.io/gpuweb/
Latest published version:
https://www.w3.org/TR/webgpu/
Feedback:
GitHub
Inline In Spec
Editors:
(Mozilla)
(Google)
(Google)
Former Editor:
(Apple)
Participate:
File an issue (open issues)
Translator:
赵凌云,lingyun.zhao@orillusion.com
薛沛,pei.xue@orillusion.com

Abstract

WebGPU API翻译文档。本翻译非官方翻译。(WebGPU 公开了一个 API,用于在图形处理单元上执行操作,例如渲染和计算。)

Status of this document

This specification was published by the GPU for the Web Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

1. 介绍

本节内容为非标准的

图形处理单元,简称GPU,对于在个人计算中实现丰富的渲染和计算应用程序至关重要。 WebGPU 是将 GPU 硬件能力公开给 web 的一组 API。该API设计自底向上有效地映射到(2014 年后)原生 GPU API。WebGPU 与 WebGL 没有关系,也不对应到 OpenGL ES。

WebGPU 将物理 GPU 硬件视为 GPUAdapter。 它通过 GPUDevice 对适配器进行连接,GPUDevice 可以用来管理资源,同时设备的 GPUQueue 可以用来执行指令。 GPUDevice 可能有自己的内存,可以高速访问处理单元。 GPUBufferGPUTexture 是 GPU 内存中的两种物理资源GPUCommandBufferGPURenderBundle 是用来存储用户记录指令的容器。 GPUShaderModule 用来存储 着色器 代码。 其他资源,将按照 GPU 使用 物理资源 的方式进行配置,例如 GPUSamplerGPUBindGroup

GPU 可以通过将数据导入管线的方式,来执行 GPUCommandBuffer 中编码的指令,这是不易编程时期和可编程时期的混合。 可编程时期,GPU可以运行着色器语言,着色器语言是专为在 GPU 硬件上运行而设计的特殊程序。管线的大部分状态通过 GPURenderPipelineGPUComputePipeline 对象来定义。 不在这些 管线 对象中的状态,是在编码时通过使用指令设置的,例如 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 端不能保证数据在边界内访问。

定义主机 API 与着色器 API 有什么不同

为了防止着色器访问了应用程序没有权限的 GPU 内存,WebGPU 的实现可能会在驱动程序中启用特殊模式(称为“鲁棒性缓冲区访问”),这种特殊访问模式保证了着色器的访问在缓冲区边界内。

另一种防止着色器越界访问的方法是,WebGPU 的实现,可以通过插入手动边界检查来转换着色器代码。当采用这种方法时,越界检查仅适用于数组索引。着色器结构的普通字段访问不需要被检查,因为 minBindingSize 的验证在主机端完成。

如果着色器尝试在物理资源边界之外加载数据,WebGPU 的实现可以允许:

  1. 在资源边界内的另一个位置返回一个值

  2. 返回带有任意“X”的“(0, 0, 0, X)”的值向量

  3. 部分丢弃绘制或调度调用

如果着色器尝试在物理资源边界之外写入数据,WebGPU 的实现可以允许:

  1. 将值写入资源边界内的另一个位置

  2. 丢弃写操作

  3. 部分丢弃绘制或调度调用

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 的设计是避免用户遭遇到现代的高精度定时攻击。 一些对象,比如 GPUBufferGPUQueue ,具有同时被访问的共享状态。因此可能会发生竞争条件,类似于多个 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. 用户代理状态

本规范没有定义任何额外的用户代理状态。 但是,需要用户代理提供编译缓存给大开销的编译,如 GPUShaderModuleGPURenderPipelineGPUComputePipeline。这些缓存对于提高 WebGPU 应用程序在第一次访问加载后的加载时间很重要。

对于规范来说,这些缓存在极其快速的编译中难以辨别,但是对于应用程序来说,很容易衡量 createComputePipelineAsync() 需要多长时间来执行。这可能会跨源泄漏信息(例如“用户是否使用此特定着色器访问了站点”),因此用户代理应遵循 存储分区 中的最佳实践。

系统的 GPU 驱动程序也可能有自己的编译着色器和管线缓存。 用户代理 可能希望尽可能禁用这些,或者采用使 GPU 驱动程序认为它们不同的方法,将每个分区的数据添加到着色器。

2.8.4. 适配器标识符

描述公开适配器信息的注意事项

注意:预计 WebGPU 将公开某些级别的信息,以识别正在使用的 GPU 适配器的类型。 这是指纹信息的潜在来源,但过去使用 WebGL 的经验表明,在某种程度上,有必要使开发人员能够创建健壮的应用程序并有效地响应用户问题。

3. 基本概念

3.1. 公约

3.1.1. 点符号语法

在此规范中,使用了通常在编程语言中被使用的 . ("点符号")语法。短语“Foo.Bar”的意思是“Foo中的 Bar成员”。

在JavaScript中被采用的 ?.(“可选链操作符”)语法也会用到。短语“Foo?.Bar”意思是,“如果 Foonullundefined ,则结果为 undefined; 否则,结果返回 Foo.Bar ”。

例如, buffer 是一个GPUBufferbuffer?.[[device]].[[adapter]] 的意思是,“如果 buffernullundefined ,则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 有以下内部槽位:

[[device]], of type device, readonly

一个内部槽位包含一个设备,该设备同时拥有内部对象

3.1.4. 对象描述符

一个对象描述符包含创建对象需要的信息,通常是通过 GPUDevice 中的某一个 create* 方法创建的。

dictionary GPUObjectDescriptorBase {
    USVString label;
};

GPUObjectDescriptorBase 有以下成员:

label, of type USVString

GPUObjectBase.label 的初始值。

3.2. 无效内部对象 & 传染无效性

WebGPU 中的对象创建操作在内部是异步的,因此它们不会因异常而失败。相反,返回的对象可能引用有效无效内部对象无效的对象可能永远不会在以后变得有效。一些对象可能在其生命周期内变得无效,而大多数可能仅在创建时才无效

如果无法创建对象,则对象从创建时就无效。例如,如果对象描述符没有描述有效的对象,或者没有足够的内存来分配资源,就会发生这种情况。

大多数类型的内部对象在创建后不会变为无效,但仍然可能变得不可用,例如 如果拥有设备丢失销毁,或者对象具有特殊的内部状态,如缓冲区状态已损坏。

某些类型的内部对象在创建后可能会变得无效;具体来说,比如设备、适配器和命令/传递/捆绑编码器。

当且仅当满足以下要求时,一个给定的GPUObjectBase 对象能与目标对象一起有效被使用:

3.3. 坐标系

Note: WebGPU 的坐标系与图形管道中的 DirectX 坐标系相匹配。

3.4. 编程模型

3.4.1. 时间线

本节内容为非标准的

前端有用户代理、后端有 GPU 的计算机系统具有并行工作在不同时间线上的组件:

内容时间线

与 Web 脚本的执行相关联。 它包括调用本规范描述的所有方法。

在内容时间线上执行的步骤如下所示。
设备时间线

与用户代理发出的 GPU 设备操作相关联。它包括创建显卡适配器、设备和 GPU 资源及状态对象,从控制 GPU 的用户代理部分的角度来看,这些操作通常是同步操作,但可以存在于单独的操作系统进程中。

在设备时间线上执行的步骤如下所示。
队列时间线

与在 GPU 的计算单元上执行操作相关。它包括在 GPU 上运行的实际绘制、复制和计算任务。

在队列时间线上执行的步骤如下所示。

在本规范中,当结果值取决于发生在除内容时间线以外的任何时间线上的工作时,将使用异步操作。它们由 JavaScript 中的回调和承诺表示。

GPUComputePassEncoder.dispatch():
  1. 用户通过调用发生在内容时间线上的 GPUComputePassEncoder 方法对 dispatch 命令进行编码。

  2. 用户调用 GPUQueue.submit() ,将 GPUCommandBuffer 移交给用户代理,用户代理通过调用操作系统驱动程序在设备时间线上执行低级提交。

  3. 队列时间线上,提交由 GPU 调度程序分发到实际计算单元上执行。

GPUDevice.createBuffer():
  1. 内容时间线上,用户填写一个 GPUBufferDescriptor,并用它创建一个 GPUBuffer

  2. 用户代理在设备时间线上创建一个低级缓冲区。

GPUBuffer.mapAsync():
  1. 用户请求在内容时间线上映射 GPUBuffer,并得到一个promise的返回值。

  2. 用户代理检查缓冲区当前是否被 GPU 使用,并在使用结束时提醒自己再次检查。

  3. 在使用缓冲区完成在队列时间线上的 GPU 操作后,用户代理将其映射到内存并决议这个 promise。

3.4.2. 内存模型

本节内容为非标准的

一旦在应用程序初始化例程中获得了GPUDevice,我们可以将 WebGPU 平台描述为由以下层组成:

  1. 实现规范的用户代理。

  2. 具有用于此设备的低级原生 API 驱动程序的操作系统。

  3. 实际的 CPU 和 GPU 硬件。

WebGPU 平台的每一层可能有不同的内存类型,用户代理在实现规范时需要考虑:

大多数物理资源分配在对 GPU 计算或渲染高效的内存类型中。当用户需要向 GPU 提供新数据时,数据可能首先需要跨越进程边界才能到达与 GPU 驱动程序通信的用户代理部分。然后这些数据可能需要对驱动程序可见,因此有时需要复制这些数据到驱动程序分配的暂存内存中。最后,这些数据可能需要被转移到专用 GPU 内存中,从而可能将内部布局更改为对 GPU 进行操作最高效的布局。

所有这些转换都是由用户代理的 WebGPU 实现完成。

Note: 这个例子描述了最坏的情况,而在实践中实现可能不需要跨越进程边界,或者可能能够将驱动程序管理的内存通过 ArrayBuffer 直接暴露给用户,从而避免任何数据复制。

3.4.3. 多线程

3.4.4. 资源使用

物理资源可以和内部使用一起在 GPU 上被使用:

输入

填入为绘制或调度调用数据的缓冲。保留内容。被缓冲区 INDEX、缓冲区 VERTEX,或缓冲区 INDIRECT允许。

常量

从着色器的角度来看是常量的资源绑定。保留内容。缓冲区 UNIFORM 或纹理 TEXTURE_BINDING 允许。

存储

可写入存储的资源绑定。被缓冲区 STORAGE 或纹理 STORAGE_BINDING 允许。

只读存储

只读存储的资源绑定。保留内容。被缓冲区 STORAGE 允许。

附件

在渲染过程中用作输出附件的纹理。被纹理 RENDER_ATTACHMENT 允许。

只读附件

在渲染过程中用作只读附件的纹理。被纹理 RENDER_ATTACHMENT 允许。

纹理可能由单独的mipmap levelsarray layers组成,它们可以在任何给定时间以不同的方式被使用。每个这样的纹理子资源都由纹理、mipmap levels和(仅适用于 2d 纹理的)array layeraspect唯一标识。

我们定义子资源可以是整个缓冲区,也可以是纹理子资源

一些内部使用与其他用法兼容。子资源可以处于将多种用途组合在一起的状态。 当(且仅当)满足以下任何规则时,我们认为列表U兼容使用列表

强制将对资源的使用仅组合到兼容使用列表中,可以让 API 限制使用内存时可能发生数据竞争的时间。该属性使对 WebGPU 编写的应用程序更有可能在不同平台上运行而无需修改。

通常,当实现以不同于当前使用允许的方式处理使用子资源的操作时,资源会被转换到新状态。 在某些情况下,例如在开放的 GPURenderPassEncoder 中,由于硬件限制,这种转换是不可能的。我们将这些地方定义为使用范围

主要的使用规则是,对于任何一个子资源,该子资源在一个使用范围内的内部使用列表必须是一个兼容使用列表

例如,在同一 GPURenderPassEncoder 中绑定相同的缓冲区用于存储输入将使编码器以及拥有的 GPUCommandEncoder 进入错误状态。这种用法组合不会形成兼容使用列表

Note: 允许在单个使用范围内出现多个可写存储缓冲区/纹理使用的竞争条件。

提供给 GPURenderPassColorAttachment.viewGPURenderPassColorAttachment.resolveTarget 的视图中包含的纹理子资源被视为用作此渲染通道使用范围附件

纹理子资源物理大小纹理子资源在纹素中的维度,包括可能的额外填充,以在子资源中形成完整的纹素块

考虑一个BC格式的 GPUTexture,其 [[descriptor]].size 为{60, 60, 1},在mipmap level 2 上对 GPUTexture 进行采样时,采样硬件使用{15, 15, 1}作为纹理子资源的大小 ,而其物理大小为 {16, 16, 1},因为块压缩算法只能在 4x4 纹素块上运行。

3.4.5. 同步

对于物理资源的每个子资源,其内部使用的标识集在队列时间线上被跟踪。

本章节将会被修订以支持多个队列。

队列时间线上,有一个有序的使用范围序列。 在每个范围的持续时间内,任何给定子资源内部使用标识集是恒定的。 子资源可以在使用范围之间的边界转换为新的使用。

本规范定义了以下使用范围

上面说的应该是GPU 指令。 但是我们还没有办法引用特定的 GPU 指令(比如 dispatch)。

上述规则意味着以下示例资源使用包含使用范围验证中:

在指令编码期间,子资源的每次使用都被记录在指令缓冲区的某一个使用范围中。对于每个使用范围,实现通过组合所有内部使用标识的列表来执行使用范围验证,这些内部使用标识的列表来自使用范围中的每个子资源。 如果这些列表中的任何一个不属于 兼容使用列表,则 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 描述符从显卡适配器创建新设备时:

任何时候用户代理需要撤销对设备的访问,都会调用丢失设备(设备,undefined)。

丢失设备(设备, 原因):
  1. 使 device.[[adapter]] 无效

  2. 使 device 无效

  3. 解释如何从设备中获得它的“主” GPUDevice

  4. 决议 device.lost 返回一个新的GPUDeviceLostInforeason 设置为 reason,并将 message 设置成一个实现定义值。

    Note: message 不应泄露不必要的用户/系统信息,也永远不应被应用程序解析。

设备通过 GPUDevice 暴露。

3.6. 可选功能

WebGPU 显卡适配器设备具有描述不同实现之间,不同的 WebGPU 功能的能力,不同的 WebGPU 功能通常是由于硬件或系统软件限制。能力要么是一个特性,要么是一个限制

3.6.1. 特性

特性是一组可选的 WebGPU 功能,通常是由于硬件或系统软件限制,并非所有实现都支持。

每个 GPUAdapter 暴露一组可用特性。只有这些特性可能在 requestDevice() 中被请求。

仅当在设备创建时请求该特性,作为该特性一部分的功能才能被使用。 通过可选特性添加到现有词典中的词典成员在 WebIDL 级别始终是可选的; 如果未启用该特性,则不得将此类成员设置为非默认值。

Note: 虽然启用特性不会添加新的 IDL 必需字段,但可能不一定与现有代码向后兼容。 一个可选特性可以启用新的验证,使以前有效的代码无效。

有关每个特性启用的功能的描述,请参阅特性索引

3.6.2. 限制

每个限制都是在设备上使用 WebGPU 的数字限制。

可支持的限制对象对每个定义的限制都有一个值。 每个显卡适配器都有一组受可支持的限制,并且创建设备具有特定的可支持的限制。 无论适配器的限制如何,都会强制执行设备限制。

每个限制都有一个默认值。每个显卡适配器都保证支持默认值或更好。如果是在 requiredLimits)中未明确指定值,则使用默认值。

一个极限值可能比另一个更好更好的限制值总是会放宽验证,从而使更多的程序有效。对于每个限制等级,都定义了“更好”。

不同的限制有不同的限制等级

最大

该限制对传递给 API 的某些值强制执行最大值。

值越高更好

只能设置为≥默认值的值。较低的值被限制为默认值。

对齐

该限制对传递给 API 的某些值强制执行最小对齐; 也就是说,该值必须是限制的倍数。

值越小更好

只能设置为≤默认值,且为2的幂的值。不是2的幂的值是无效的。2的较高幂被限制为默认值。

Note: 设置“更好”的限制不一定是可取的,因为它们可能会影响性能。因此,为了提高跨设备和实现的可移植性,应用程序通常应该请求适用于其内容的“最差”限制(理想情况下,默认值)。

限制名称 类型 限制等级 默认
maxTextureDimension1D GPUSize32 最大 8192
通过 dimension "1d" 创建的纹理,所允许的 size.width 的最大值。
maxTextureDimension2D GPUSize32 最大 8192
通过 dimension "2d" 创建的纹理,所允许的 size.widthsize.height 的最大值。
maxTextureDimension3D GPUSize32 最大 2048
通过 dimension "3d" 创建的纹理,所允许的 size.width, size.heightsize.depthOrArrayLayers 的最大值。
maxTextureArrayLayers GPUSize32 最大 256
通过 dimension "1d""2d" 创建的纹理,所允许的 size.depthOrArrayLayers 的最大值。
maxBindGroups GPUSize32 最大 4
创建 GPUPipelineLayout 时,bindGroupLayouts 中所允许的 GPUBindGroupLayouts 的最大值。
maxDynamicUniformBuffersPerPipelineLayout GPUSize32 最大 8
GPUPipelineLayoutGPUBindGroupLayoutEntry 输入接口的最大数量,这些输入接口是具有动态偏移的统一缓冲区。 详见超出绑定槽限制
maxDynamicStorageBuffersPerPipelineLayout GPUSize32 最大 4
GPUPipelineLayoutGPUBindGroupLayoutEntry 条目的最大数量,这些条目是具有动态偏移的存储缓冲区。 详见超出绑定槽限制
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.offsetsetBindGroup dynamicOffsets 参数所需的对齐方式,这个条目 entry.buffer?.type"uniform"
minStorageBufferOffsetAlignment GPUSize32 对齐 256
GPUBindGroupLayoutEntry条目做绑定时,GPUBufferBinding.offsetsetBindGroup dynamicOffsets 参数所需的对齐方式,这个条目 entry.buffer?.type"storage""read-only-storage"
maxVertexBuffers GPUSize32 最大 8
创建 GPURenderPipelinebuffers 的最大值。
maxVertexAttributes GPUSize32 最大 16
创建 GPURenderPipeline 时在所有 buffersattributes 的最大值。
maxVertexBufferArrayStride GPUSize32 最大 2048
创建 GPURenderPipelinearrayStride 所允许的的最大值。
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.limitsGPUDevice.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>;
};
Note: GPUSupportedFeaturesset entries的类型是 DOMString,以允许用户代理优雅地处理有效的 GPUFeatureNames,这些GPUFeatureNames在规范的后续版本中添加,但用户代理尚未更新以识别。如果设置的条目类型是 GPUFeatureName,以下代码将产生TypeError 而不是报告 false
检查对无法识别的功能的支持:
if (adapter.features.has('unknown-feature')) {
    // Use unknown-feature
} else {
    console.warn('unknown-feature is not supported by this adapter.');
}

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. 初始化

GPU 对象分别通过 NavigatorWorkerNavigator 接口在 WindowDedicatedWorkerGlobalScope 上下文中可用, 并通过 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?>

  1. promise 成为一个 a new promise.

  2. this 设备时间线上执行以下步骤 :

    1. 如果用户代理选择返回一个适配器,用户代理应该:

      1. 创建一个有效显卡适配器 adapter,根据§ 4.2.1 适配器选择规则和 options 标准进行选择。

      2. 如果 adapter 满足应急适配器的标准,设定 adapter.[[fallback]]true.

      3. 使用新的 GPUAdapter 封装 adapter,来决议 promise.

    2. 否则, promise 决议null.

  3. 返回 promise.

GPU 有以下内部插槽:

[[previously_returned_adapters]], of type ordered set<adapter>

通过 requestAdapter() 返回的显卡适配器集。 在标记适配器过时中,显卡适配器被使用,然后被清除。

当系统状态发生任何变化,并可能影响任何 requestAdapter() 的调用结果时,用户代理应该标记适配器过时。 例如:

此外,标记适配器过时可以随时被调用。即使没有系统状态改变,用户代理也可以经常选择调用(例如,最后一次调用 requestDevice() 后几秒)。这对格式良好的应用程序没有影响,模糊了真实的系统状态变化,并使 开发人员更清楚的了解了,在调用 requestDevice() 之前,总是需要再次调用 requestAdapter()

标记适配器过时:
  1. 对于在 navigator.gpu.[[previously_returned_adapters]] 中的每一个adapter:

    1. 使adapter.[[adapter]] 无效

  2. 清空 navigator.gpu.[[previously_returned_adapters]].

如果引入了 adaptersAdded/adapterschanged 事件,请在此处更新。

无提示的获取一个 GPUAdapter:
const gpuAdapter = await navigator.gpu.requestAdapter();

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 to false

当设置为 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<GPUDevice>

  1. promise 成为一个 a new promise.

  2. adapter 作为 this.[[adapter]].

  3. 设备时间线上执行以下步骤:

    1. 如果以下任意条件没有满足,通过生成 TypeError reject promise,然后停止运行。

      Note: 如果是浏览器根本不知道的特性名称(在其 GPUFeatureName 定义中),则会产生相同的错误。这将浏览器不支持某个特性时的行为与特定适配器不支持某个特性时的行为融合在一起。

    2. 如果以下任意条件没有满足,通过生成 OperationError reject promise,然后停止运行。

    3. 如果 adapter无效,或者用户代理无法满足请求:

      1. device 成为一个新的设备.

      2. 丢失设备(device, undefined).

        Note: 这将使 adapter 无效, 如果之前不是。

        Note: 发生这种情况时,用户代理应考虑在大多数或所有情况下发出开发人员可见的警告。 应用程序应该从 requestAdapter() 开始执行重新初始化逻辑。

      3. 用一个新的 GPUDevice 来封装 device,并决议 promise,然后停止运行。

    4. 用一个新的 GPUDevice 对象封装新设备,并决议 promise,新设备具有 descriptor 描述的功能。

  4. 返回 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 {}

指定设备请求所需的限制。如果适配器无法提供这些限制,则请求将失败。

每个key必须是支持的限制的成员名称。正如指定的限制,没有更好或更糟,才会被允许由生成的设备上的 API 调用验证。

如果支持,请求一个具有 "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()

销毁设备,防止对其进行进一步操作。未完成的异步操作将失败。

Note: 由于此设备上不能发生进一步的操作,因此实现可以释放资源分配,并立即中止未完成的异步操作。

GPUDevice 对象是 serializable objects

完成定义多线程 API,并将“[Serializable]”添加回接口。 [Issue #gpuweb/gpuweb#354]

序列化 GPUDevice 对象的步骤;给定 value, serializedforStorage:
  1. 设置 serialized.agentCluster 为surrounding agent代理集群

  2. 如果 serialized.agentCluster 的cross-origin isolated capability 为 false,则返回 “DataCloneError”。

  3. 如果 forStoragetrue,返回 “DataCloneError”。

  4. serialized.device 设置为 value.[[device]] 的值。

反序列化 GPUDevice 对象的步骤;给定 serializedvalue:
  1. 如果 serialized.agentCluster 不是surrounding agent代理集群,则返回 “DataCloneError”。

  2. value.[[device]] 设置为 serialized.device。

GPUDevice 并不真正需要跨域策略限制。无论如何,应该可以从多个代理使用。一旦我们描述了缓冲区、纹理和队列的序列化 - COOP+COEP 逻辑应该被移到那里。

4.5. 示例

一个更具有鲁棒性的的请求 GPUAdapterGPUDevice 的示例,该示例还包含了错误处理:
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 type GPUSize64.

GPUBuffer 被分配的长度(以字节为单位)。

[[usage]] of type GPUBufferUsageFlags.

GPUBuffer 被允许的使用。

[[state]] of type buffer state.

GPUBuffer 的当前状态。

[[mapping]] of type ArrayBuffer or Promise or null.

GPUBuffer 的映射。ArrayBuffer 不能直接被访问,而是通过视图去访问,称为映射范围,被存储在 [[mapped_ranges]] 中。

DataBlock方面指定 [[mapping]] 类似于 AllocateArrayBuffer[Issue #gpuweb/gpuweb#605]

[[mapping_range]] of type list<unsigned long long> or null.

此被映射的 GPUBuffer 的范围。

[[mapped_ranges]] of type list<ArrayBuffer> or null.

ArrayBuffers 通过 getMappedRange 返回给应用程序。这些 ArrayBuffers 会被追踪,以便在 unmap 被调用时可以将其分离。

[[map_mode]] of type GPUMapModeFlags.

最后一次调用 mapAsync()GPUMapModeFlags(如果有)。

[[usage]][[descriptor]].usage 的命名不同。我们应该让两种命名保持一致。

每个 GPUBuffer内容时间线上都有一个当前的缓冲区状态,它是以下几项之一:

Note: 一旦创建了 GPUBuffer[[size]][[usage]] 是不可变的。

Note: GPUBuffer 有一个具有以下状态的状态机。(([[mapping]], [[mapping_range]], 并且 [[mapped_ranges]] 在未指定时为空。)

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;
};
校验 GPUBufferDescriptor(device, descriptor)
  1. 如果设备缺失,返回 false.

  2. 如果 descriptorusage 中任何一个标志位都不属于设备的 [[allowed buffer usages]],返回 false

  3. 如果 descriptorusage 中的 MAP_READMAP_WRITE 标志位都有值,返回 false

  4. 返回 true.

5.2.2. 缓冲区使用

typedef [EnforceRange] unsigned long GPUBufferUsageFlags;
[Exposed=(Window, DedicatedWorker)]
namespace GPUBufferUsage {
    const GPUFlagsConstant MAP_READ      = 0x0001;
    const GPUFlagsConstant MAP_WRITE     = 0x0002;
    const GPUFlagsConstant COPY_SRC      = 0x0004;
    const GPUFlagsConstant COPY_DST      = 0x0008;
    const GPUFlagsConstant INDEX         = 0x0010;
    const GPUFlagsConstant VERTEX        = 0x0020;
    const GPUFlagsConstant UNIFORM       = 0x0040;
    const GPUFlagsConstant STORAGE       = 0x0080;
    const GPUFlagsConstant INDIRECT      = 0x0100;
    const GPUFlagsConstant QUERY_RESOLVE = 0x0200;
};
createBuffer(descriptor)

创建一个 GPUBuffer

调用: GPUDevice this.

参数:

Arguments for the GPUDevice.createBuffer(descriptor) method.
Parameter Type Nullable Optional Description
descriptor GPUBufferDescriptor 要创建的 GPUBuffer 的描述。

返回: GPUBuffer

  1. 如果以下任何条件没有满足,返回一个错误缓冲区并停止。

    解释什么是 GPUDevice[[allowed buffer usages]]. [Issue #gpuweb/gpuweb#605]

Note: 如果缓冲区创建失败,并且 descriptor.mappedAtCreationfalse,对 mapAsync() 的任何调用都将被拒绝,因此开始映射中分配的任何资源都可以并且可能会被丢弃或回收。

  1. 使 b 为一个新的 GPUBuffer 对象.

  2. b.[[size]] 设置为 descriptor.size.

  3. b.[[usage]] 设置为 descriptor.usage.

  4. 如果 descriptor.mappedAtCreation 值为 true:

    1. b.[[mapping]] 设置为一个新的大小为 b.[[size]]ArrayBuffer

    2. b.[[mapping_range]] 设置为 [0, descriptor.size].

    3. b.[[mapped_ranges]] 设置为 [].

    4. b.[[state]] 设置为在创建时被映射状态.

    否则:

    1. b.[[mapping]] 设置为 null

    2. b.[[mapping_range]] 设置为 null

    3. b.[[mapped_ranges]] 设置为 null

    4. b.[[state]] 设置为未映射状态。

  5. b 分配的每个字节设置为零。

  6. 返回 b.

Note:usage 中没有 MAP_READMAP_WRITE 的情况下,将 mappedAtCreation 设置为 true是有效的。这可用于设置缓冲区的初始数据。

创建一个 128 字节,并且可以被写入的统一缓冲区:
const buffer = gpuDevice.createBuffer({
    size: 128,
    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});

5.3. 缓冲区销毁

不再需要 GPUBuffer 的应用程序可以选择通过调用 {{GPUBuffer/destroy()},在垃圾回收之前,丢弃对缓冲区的访问。销毁缓冲区的同时,也使缓冲区回到未映射状态,释放为映射分配的任何内存。

Note: 一旦先前提交的所有使用 GPUBuffer 的操作完成,用户代理可以回收与 GPUBuffer 关联的 GPU 内存。

destroy()

销毁 GPUBuffer.

调用: GPUBuffer this.

返回: undefined

  1. 如果 this.[[state]] 不是未映射被销毁

    1. 执行取消映射 this 的步骤。

  2. 设置 this.[[state]]被销毁.

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 READ  = 0x0001;
    const GPUFlagsConstant WRITE = 0x0002;
};
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 以字节为单位的要映射的范围大小。

返回: Promise<undefined>

一旦我们有了错误单子的描述,即刻处理错误缓冲区。 [Issue #gpuweb/gpuweb#605]

  1. 如果 size 字段丢失:

    1. 使 rangeSize 为 max(0, this.[[size]] - offset)。

    否则, 使 rangeSizesize

  2. 如果以下任何条件未被满足:

    我们是否需要对仅包含有效标识的 mode 做校验?

    接下来:

    1. 记录当前范围内的校验错误。

    2. 返回 a promise rejected with 一个设备时间线上的 OperationError

  3. 使 p 为一个新的 Promise

  4. 设置 this.[[mapping]]p

  5. 设置 this.[[state]]待映射

  6. 设置 this.[[map_mode]]mode

  7. 在默认队列上的队列时间线对操作进行入队操作,该行为将执行以下操作:

    1. 如果 this.[[state]]待映射状态:

      1. 使 m 为一个新的大小为 rangeSizeArrayBuffer

      2. m 的内容设置为 this 分配的内容,从偏移 offset 开始分配,且分配 rangeSize 字节。

      3. this.[[mapping]] 设置为 m.

      4. this.[[state]] 设置为已映射.

      5. this.[[mapping_range]] 设置为 [offset, offset + rangeSize].

      6. this.[[mapped_ranges]] 设置为 [].

    2. Resolve p.

  8. 返回 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

  1. 如果 size 缺失:

    1. 使 rangeSize 为 max(0, this.[[size]] - offset)。

    否则, 使 rangeSizesize

  2. 如果任何以下条件未满足, 产生一个 OperationError 异常并停止。

    Note: 获取在创建时被映射GPUBuffer 的映射范围总是有效的,即使它是无效的,因为内容时间线可能不知道它是无效的。

    考虑将 mapAsync 偏移量对齐到 8 以匹配此值。

  3. 使 m 为一个新的大小为 rangeSizeArrayBuffer,指向 this.[[mapping]] 的内容偏移量 offset - this.[[mapping_range]][0]。

  4. 添加 (Append) mthis.[[mapped_ranges]]

  5. 返回m

unmap()

对已映射的 GPUBuffer 范围取消映射,并且使得其内容可以重新被 GPU 使用。

调用: GPUBuffer this.

返回: undefined

  1. 如果以下任何需求没有满足,产生一个校验错误并停止。

    Note: 取消一个状态为在创建时被映射GPUBuffer 无效映射是有效的,因为内容时间线可能不知道它是个错误的 GPUBuffer。这允许释放临时 [[mapping]] 内存。

  2. 如果 this.[[state]]待映射:

    1. 拒绝 [[mapping]],产生一个 AbortError

    2. 设置 this.[[mapping]]null

  3. 如果 this.[[state]]已映射在创建时被映射:

    1. 如果以下两条件之一成立:

      则接下来:

      1. 在默认队列的队列时间线上将操作入队,该操作将 this.[[mapping_range]]this 分配更新为 this.[[mapping]] 的内容。

    2. this.[[mapped_ranges]] 中的每个 ArrayBuffer 与其内容分离。

    3. this.[[mapping]] 设置为 null.

    4. this.[[mapping_range]] 设置为 null.

    5. this.[[mapped_ranges]] 设置为 null.

  4. this.[[state]] 设置为未映射.

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

如果纹理被破坏,该纹理就不能再用于任何操作,并且其底层内存可以被释放。

compute render extent(baseSize, mipLevel)

参数:

返回: GPUExtent3DDict

  1. extent 成为一个新的 GPUExtent3DDict 对象。

  2. 设置 extent.width 为 max(1, baseSize.widthmipLevel).

  3. 设置 extent.height 为 max(1, baseSize.heightmipLevel).

  4. 设置 extent.depthOrArrayLayers 为 1.

  5. 返回 extent.

与描述抽样的规范部分共享此定义。

6.1.1. 纹理创建

dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
    required GPUExtent3D size;
    GPUIntegerCoordinate mipLevelCount = 1;
    GPUSize32 sampleCount = 1;
    GPUTextureDimension dimension = "2d";
    required GPUTextureFormat format;
    required GPUTextureUsageFlags usage;
    sequence<GPUTextureFormat> viewFormats = [];
};
viewFormats, of type sequence<GPUTextureFormat>, defaulting to []

当在此纹理(除了纹理的实际格式 format)调用 createView() 时,指定了何种视图 format 值可以被允许。

Note: 将格式添加到此列表可能会对性能产生相当大的影响,具体取决于用户的系统。最好避免不必要地添加格式。

此列表中的格式与纹理格式一起必须为纹理视图格式可兼容的

两个GPUTextureFormats formatviewFormat纹理视图格式可兼容的当:
  • format 等于 viewFormat, 或

  • formatviewFormat 的区别仅在于它们是否为 srgb 格式(拥有 -srgb 后缀)。

定义更大的兼容性类。 [Issue #gpuweb/gpuweb#168]

enum GPUTextureDimension {
    "1d",
    "2d",
    "3d",
};
typedef [EnforceRange] unsigned long GPUTextureUsageFlags;
[Exposed=(Window, DedicatedWorker)]
namespace GPUTextureUsage {
    const GPUFlagsConstant COPY_SRC          = 0x01;
    const GPUFlagsConstant COPY_DST          = 0x02;
    const GPUFlagsConstant TEXTURE_BINDING   = 0x04;
    const GPUFlagsConstant STORAGE_BINDING   = 0x08;
    const GPUFlagsConstant RENDER_ATTACHMENT = 0x10;
};
maximum mipLevel count(dimension, size) 参数:
  1. 计算最大维度值 m:

  2. 返回 floor(log2(m)) + 1.

createTexture(descriptor)

创建一个 GPUTexture.

调用: GPUDevice this.

参数:

Arguments for the GPUDevice.createTexture(descriptor) method.
Parameter Type Nullable Optional Description
descriptor GPUTextureDescriptor 针对要创建的 GPUTexture 的描述。

返回: GPUTexture

  1. this设备时间线上执行以下步骤:

    1. 如果 descriptor.format 是一个需要某个特性的 GPUTextureFormat(参见 § 25.1 纹理格式功能),但 this.[[device]].[[features]] 没有包含该特性,返回 TypeError

    2. 如果不满足以下任何要求:

      Then:

      1. 在当前范围内生成带有相应错误消息的 GPUValidationError

      2. 返回一个新的无效 GPUTexture

    3. t 成为一个新的 GPUTexture 对象.

    4. 设定 t.[[descriptor]]descriptor.

    5. 返回 t.

创建一个具有一个 array layer 和一个 mip level 的 16x16,RGBA,2D纹理:
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.

调用: GPUTexture this.

返回: undefined

  1. 设置 this.[[destroyed]] 为 true.

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 aspect = "all";
    GPUIntegerCoordinate baseMipLevel = 0;
    GPUIntegerCoordinate mipLevelCount;
    GPUIntegerCoordinate baseArrayLayer = 0;
    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 类型。

  1. 设置 descriptor 为带有descriptorresolving GPUTextureViewDescriptor defaults 返回值。

  2. this设备时间线上发布以下指令:

    1. 如果不满足以下任何要求:

      Then:

      1. 在当前范围内生成一个 GPUValidationError 并带有适当的错误消息。

      2. 返回一个新的无效 GPUTextureView

    2. view 成为一个新的 GPUTextureView 对象。

    3. 设置 view.[[texture]]this

    4. 设置 view.[[descriptor]]descriptor.

    5. 如果 this.[[descriptor]].usage 包含 RENDER_ATTACHMENT:

      1. renderExtentcompute render extent(this.[[descriptor]].size, descriptor.baseMipLevel).

      2. 设置 view.[[renderExtent]]renderExtent.

    6. 返回 view.

When resolving GPUTextureViewDescriptor defaults for GPUTextureViewDescriptor descriptor 运行一下步骤:
  1. resolved 成为一个 descriptor 的副本。

  2. 如果 resolved.formatundefined, 设置 resolved.formattexture.[[descriptor]].format.

  3. 如果 resolved.mipLevelCountundefined, 设置 resolved.mipLevelCounttexture.[[descriptor]].mipLevelCountbaseMipLevel.

  4. 如果 resolved.dimensionundefined 并且 texture.[[descriptor]].dimension 是:

    "1d"

    设置 resolved.dimension"1d".

    "2d"

    设置 resolved.dimension"2d".

    "3d"

    设置 resolved.dimension"3d".

  5. 如果 resolved.arrayLayerCountundefined 并且 resolved.dimension 是:

    "1d", "2d", or "3d"

    设置 resolved.arrayLayerCount1.

    "cube"

    设置 resolved.arrayLayerCount6.

    "2d-array" 或者 "cube-array"

    设置 resolved.arrayLayerCounttexture.[[descriptor]].size.depthOrArrayLayersbaseArrayLayer.

  6. 返回 resolved.

要确定 GPUTexture texturearray layer count,请运行 以下步骤:
  1. 如果 texture.[[descriptor]].dimension 是:

    "1d" 或者 "3d"

    返回 1.

    "2d"

    返回 texture.[[descriptor]].size.depthOrArrayLayers.

当且仅当以下条件为真,两个 GPUTextureView 对象 ab 被作为 texture-view-aliasing

问题: 用“一组子资源”算法来描述这个算法。

6.3. 纹理格式

格式的名称指定了组件的顺序、每个组件的位数、和组件的数据类型。

如果格式具有 “-srgb” 后缀,则在着色器中读取和写入颜色值期间应用从伽马到线性的 sRGB 转换,反之亦然。 压缩纹理格式由特性提供。其命名应遵循此处的约定,以纹理名称作为前缀。 例如 etc2-rgba8unorm

纹素块 是基于像素的 GPUTextureFormat 中纹理的单个可寻址元素,以及基于块的压缩 GPUTextureFormat 中纹理的单个压缩块。

纹素块宽度纹素块高度 指定了一个纹素块的尺寸。

GPUTextureFormat纹素块大小是存储一个纹素块的字节数。 除了 "stencil8""depth24plus" 和 {{GPUTextureFormat/"depth24plus-stencil8"} 之外,每个 GPUTextureFormat纹素块大小是恒定的。

enum GPUTextureFormat {
    // 8-bit 格式
    "r8unorm",
    "r8snorm",
    "r8uint",
    "r8sint",

    // 16-bit 格式
    "r16uint",
    "r16sint",
    "r16float",
    "rg8unorm",
    "rg8snorm",
    "rg8uint",
    "rg8sint",

    // 32-bit 格式
    "r32uint",
    "r32sint",
    "r32float",
    "rg16uint",
    "rg16sint",
    "rg16float",
    "rgba8unorm",
    "rgba8unorm-srgb",
    "rgba8snorm",
    "rgba8uint",
    "rgba8sint",
    "bgra8unorm",
    "bgra8unorm-srgb",
    // Packed 32-bit formats
    "rgb9e5ufloat",
    "rgb10a2unorm",
    "rg11b10ufloat",

    // 64-bit 格式
    "rg32uint",
    "rg32sint",
    "rg32float",
    "rgba16uint",
    "rgba16sint",
    "rgba16float",

    // 128-bit 格式
    "rgba32uint",
    "rgba32sint",
    "rgba32float",

    // 深度/模板格式
    "stencil8",
    "depth16unorm",
    "depth24plus",
    "depth24plus-stencil8",
    "depth32float",

    // "depth24unorm-stencil8"特性
    "depth24unorm-stencil8",

    // "depth32float-stencil8"特性
    "depth32float-stencil8",

    // BC 压缩模式非常有用,如果设备和用户代理同时支持 "texture-compression-bc"
    // 并且在 RequestDevice 中被开启。
    "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",
    "bc7-rgba-unorm-srgb",

    // 如果设备/用户代理支持并在 requestDevice 中启用 “texture-compression-etc2”,则 ETC2 压缩格式可用。
    "etc2-rgb8unorm",
    "etc2-rgb8unorm-srgb",
    "etc2-rgb8a1unorm",
    "etc2-rgb8a1unorm-srgb",
    "etc2-rgba8unorm",
    "etc2-rgba8unorm-srgb",
    "eac-r11unorm",
    "eac-r11snorm",
    "eac-rg11unorm",
    "eac-rg11snorm",

    // 如果设备/用户代理支持并在 requestDevice 中启用 “texture-compression-astc”,则 ASTC 压缩格式可用。
    "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 绑定组布局的输入成员,被绑定到绑定组布局。外部纹理使用多个绑定槽:参见超出绑定槽限制

外部纹理可以在不创建导入源的副本的情况下实现,但这取决于实现定义的因素。底层表示的所有权可能是独占的,也可能与其他所有者(例如视频解码器)共享,但这对应用程序不可见。

外部纹理的底层表示是不可见的(采样行为除外),但通常可能包括

使用的配置可能在时间、系统、用户代理、媒体源、或单个视频源的帧中发生变化。为了用于尽可能多的表示,对于每个外部纹理,绑定保守地使用以下内容:

[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUExternalTexture {
};
GPUExternalTexture includes GPUObjectBase;

GPUExternalTexture 有以下内部插槽:

[[destroyed]], boolean 格式

表示对象是否被摧毁 (不能被使用)。初始被设定为 false.

6.4.1. 导入外部纹理

外部纹理是使用 importExternalTexture() 从外部视频对象创建的。

使用画布更新此描述。

外部纹理作为一个微任务,会被自动销毁,而不是像其他资源一样被手动销毁或被当垃圾收集。

dictionary GPUExternalTextureDescriptor : GPUObjectDescriptorBase {
    required HTMLVideoElement source;
    GPUPredefinedColorSpace colorSpace = "srgb";
};
importExternalTexture(descriptor)

创建一个 GPUExternalTexture 包装提供的图像源。

调用: GPUDevice this.

参数:

Arguments for the GPUDevice.importExternalTexture(descriptor) method.
Parameter Type Nullable Optional Description
descriptor GPUExternalTextureDescriptor 提供外部图像源对象(和任何创建选项)。

返回: GPUExternalTexture

  1. source 成为 descriptor.source.

  2. usability 是 检查图像参数的可用性|检查 source 的可用性的结果 (这可能会引发异常)。

  3. 如果 usabilitybad, 返回一个 InvalidStateError 并停止运行。

  4. 如果 source is not origin-clean, 返回一个 SecurityError 并停止运行。

  5. datasource 的当前图像内容转换的结果进入未预乘 alpha 颜色空间 descriptor.colorSpace

may result 值超出范围 [0, 1]。如果需要做夹紧保护,可以在取样后进行。

Note: 这被描述为一个副本,但可以作为对只读基础数据的引用,以及稍后执行转换的适当元数据来实现。

  1. result 是一个新的 GPUExternalTexture 对象包装 data

  2. Queue a microtaskresult.[[destroyed]] 设置为 true,并释放底层资源。

    这是否过于严格?

  3. 返回 result.

const externalTexture = gpuDevice.importExternalTexture({
    source: videoElement
});

6.4.2. 采样外部纹理

外部纹理在 WGSL 中用 texture_external 表示,可以使用 textureLoadtextureSampleLevel

提供给 textureSampleLevelsampler 用于对底层纹理进行采样。结果在 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 type GPUSamplerDescriptor, readonly

用于创建 GPUSamplerGPUSamplerDescriptor

[[isComparison]] of type boolean.

用于表示 {GPUSampler}} 是否被当作比较采样器。

[[isFiltering]] of type boolean.

用于表示 GPUSampler 是否对纹理的多个样本进行加权。

7.2. 采样器创建

7.2.1. GPUSamplerDescriptor

GPUSamplerDescriptor 指定用于创建 GPUSampler 的选项。

dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
    GPUAddressMode addressModeU = "clamp-to-edge";
    GPUAddressMode addressModeV = "clamp-to-edge";
    GPUAddressMode addressModeW = "clamp-to-edge";
    GPUFilterMode magFilter = "nearest";
    GPUFilterMode minFilter = "nearest";
    GPUFilterMode mipmapFilter = "nearest";
    float lodMinClamp = 0;
    float lodMaxClamp = 32;
    GPUCompareFunction compare;
    [Clamp] unsigned short maxAnisotropy = 1;
};

解释 LOD 是如何计算的,以及平台之间是否存在差异。

解释什么是各向异性采样。

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"

永远通过比较测试。

validating GPUSamplerDescriptor(device, descriptor) 参数:

返回: boolean

当且仅当满足下列条件时,返回 true

createSampler(descriptor)

创建一个 GPUBindGroupLayout

调用: GPUDevice this.

参数:

Arguments for the GPUDevice.createSampler(descriptor) method.
Parameter Type Nullable Optional Description
descriptor GPUSamplerDescriptor 要创建的 GPUSampler 的描述。

返回: GPUSampler

  1. 使 s 为一个新的 GPUSampler 对象。

  2. 将| s|.[[descriptor]] 设置为 descriptor.

  3. 如果 s.[[descriptor]]compare 属性为 null 或者 undefined,将 s.[[isComparison]] 设置为 false,否则,设置为 true

  4. 如果 minFiltermagFiltermipmapFilter 中没有一个值为 "linear",则将 s.[[isFiltering]] 设置为 false,否则,设置为 true

  5. 返回 s

有效使用
创建一个执行三线性过滤并重复纹理坐标的 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 VERTEX   = 0x1;
    const GPUFlagsConstant FRAGMENT = 0x2;
    const GPUFlagsConstant COMPUTE  = 0x4;
};

dictionary GPUBindGroupLayoutEntry {
    required GPUIndex32 binding;
    required GPUShaderStageFlags visibility;

    GPUBufferBindingLayout buffer;
    GPUSamplerBindingLayout sampler;
    GPUTextureBindingLayout texture;
    GPUStorageTextureBindingLayout storageTexture;
    GPUExternalTextureBindingLayout externalTexture;
};

GPUBindGroupLayoutEntry 词典有以下成员:

binding, of type GPUIndex32

GPUBindGroupLayoutEntry 中资源绑定的唯一标识符、相应的 GPUBindGroupEntryGPUShaderModule

visibility, of type GPUShaderStageFlags

GPUShaderStage 成员的比特集。 每个设置位表示 GPUBindGroupLayoutEntry 的资源 可以从关联的着色器阶段访问。

buffer, of type GPUBufferBindingLayout

当不是 undefined 时,表示这个 GPUBindGroupLayoutEntrybinding resource typeGPUBufferBinding

sampler, of type GPUSamplerBindingLayout

当不是 undefined 时,表示这个 GPUBindGroupLayoutEntrybinding resource typeGPUSampler

texture, of type GPUTextureBindingLayout

当不是 undefined 时,表示这个 GPUBindGroupLayoutEntrybinding resource typeGPUTextureView

storageTexture, of type GPUStorageTextureBindingLayout

当不是 undefined 时,表示这个 GPUBindGroupLayoutEntrybinding resource typeGPUTextureView

externalTexture, of type GPUExternalTextureBindingLayout

当不是 undefined 时,表示这个 GPUBindGroupLayoutEntrybinding resource typeGPUExternalTexture

GPUBindGroupLayoutEntrybinding member 由定义了 GPUBindGroupLayoutEntry 的哪个成员决定: buffersamplertexturestorageTextureexternalTexture。 对于任何给定的 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
如果用于限制的插槽数超过 limits 中支持的值, GPUBindGroupLayoutEntry 值的 list entries exceeds the binding slot limitsxi supported limits limits。 每个条目可以使用多个槽来实现多个限制。
  1. 对于每个 在 entries 中的 entry , 如果:

    entry.buffer?.type"uniform"entry.buffer?.hasDynamicOffsettrue

    1 maxDynamicUniformBuffersPerPipelineLayout 槽会被使用。

    entry.buffer?.type"storage"entry.buffer?.hasDynamicOffsettrue

    1 maxDynamicStorageBuffersPerPipelineLayout 槽会被使用。

  2. 对于每个着色器阶段 stage 在 « VERTEX, FRAGMENT, COMPUTE »:

    1. 对于每个 在 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 槽, 1 maxSamplersPerShaderStage 槽, 和 1 maxUniformBuffersPerShaderStage 槽会被使用。

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 to false

指示此绑定是否需要动态偏移量。

minBindingSize, of type GPUSize64, defaulting to 0

指示最小缓冲区绑定大小。

绑定始终在 createBindGroup() 中针对此大小进行验证。

如果此 * 不是 * 0,则额外创建管线 validates,这个值对于着色器中声明的绑定足够大。

如果此 * 是 * 0,则另外绘制/发送命令 validateGPUBindGroup 中的每个绑定对于着色器中声明的绑定都足够大。

指示最小缓冲区绑定大小。

绑定始终在 createBindGroup() 中针对此大小进行验证。

如果此 * 不是 * 0,则额外创建管道 validates 这个值对于着色器中声明的绑定足够大。

如果此 * 是 * 0,则另外绘制/发送命令 validate GPUBindGroup 中的每个绑定对于着色器中声明的绑定都足够大。

注意:对于为早期验证指定的其他绑定相关字段,类似的执行时间验证在理论上是可能的,例如 sampleTypeformat,目前只能在管线创建中进行验证。然而,这种执行时间验证可能成本高昂或不必要地复杂,因此它仅适用于预计具有最符合人体工程学影响的 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 to false

指示绑定到此绑定的纹理视图是否必须进行多重采样。

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 的描述。

返回: GPUBindGroupLayout

  1. layout 是一个新的有效 GPUBindGroupLayout 对象。

  2. 设置 layout.[[descriptor]]descriptor.

  3. thisDevice timeline 上发出以下步骤:

    1. 如果一下任一条件没有被满足:

      Then:

      1. 在当前范围内产生一个带有适当错误消息的GPUValidationError

      2. 使 layout invalid 并且返回 layout

    2. Set layout.[[dynamicOffsetCount]] to the number of entries in descriptor where buffer is not undefined and buffer.hasDynamicOffset is true.

    3. For each GPUBindGroupLayoutEntry entry in descriptor.entries:

      1. Insert entry into layout.[[entryMap]] with the key of entry.binding.

  4. 返回 layout.

8.1.2. 兼容性

两个 GPUBindGroupLayout 对象 abgroup-equivalent 当且仅当满足以下所有条件:

如果绑定组布局是 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 offset = 0;
    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

  1. 设定 bindGroup 为一个新的有效的 GPUBindGroup 对象。

  2. 设定 limitsthis.[[device]].[[limits]]

  3. thisDevice timeline 发布一下步骤:

    1. 如果以下任一条件没有被满足:

      • descriptor.layoutthis 一起使用是有效的。

      • descriptor.layoutentries 的数量和 descriptor.entries 的数量完全相等。

      对于每一个 descriptor.entries 中的 GPUBindGroupEntry bindingDescriptor:

      Then:

      1. 在当前范围内产生一个带有适当错误消息的GPUValidationError

      2. 使 bindGroup invalid 并返回 bindGroup.

    2. 设置 bindGroup.[[layout]] = descriptor.layout.

    3. 设置 bindGroup.[[entries]] = descriptor.entries.

    4. 设置 bindGroup.[[usedResources]] = {}.

    5. descriptor.entries 中的每一个 GPUBindGroupEntry bindingDescriptor:

      1. 设定 internalUsagebinding usage 为了 layoutBinding

      2. resource 看到的每个 subresource 添加到 [[usedResources]] 作为 internalUsage

  4. 返回 bindGroup.

问题:单独定义“有效缓冲区绑定大小”。

effective buffer binding size(binding)
  1. 如果 binding.sizeundefined:

    1. 返回 max(0, binding.buffer.[[size]] - binding.offset);

  2. 返回 binding.size.

当且仅当以下条件为真,两个 GPUBufferBinding 对象 ab 被作为 buffer-binding-aliasing

问题:定义当大小可以为 undefined 时区间如何被 offset/size 构成。

8.3. GPUPipelineLayout

GPUPipelineLayout 定义了在 setBindGroup 中的命令编码期间设置的所有 GPUBindGroup 对象的资源和由设置的管道着色器之间的映射GPURenderEncoderBase.setPipelineGPUComputePassEncoder.setPipeline

资源的完整绑定地址可以定义为以下三项:

  1. 着色器阶段蒙版,资源可见

  2. 绑定组索引

  3. 绑定号码

这个地址的组成部分也可以看作是一个管道的绑定空间。 GPUBindGroup(带有相应的 GPUBindGroupLayout)覆盖了固定绑定组索引的空间。 包含的绑定需要是着色器在此绑定组索引处使用的资源的超集。

[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUPipelineLayout {
};
GPUPipelineLayout includes GPUObjectBase;

GPUPipelineLayout 有以下内部插槽:

[[bindGroupLayouts]] list<GPUBindGroupLayout> 类型。

GPUPipelineLayoutDescriptor.bindGroupLayouts 中创建时提供的 GPUBindGroupLayout 对象。

注意:对许多 GPURenderPipelineGPUComputePipeline 管道使用相同的 GPUPipelineLayout 可以保证用户代理在这些管道之间切换时不需要在内部重新绑定任何资源。

GPUComputePipeline 对象 X 是由 GPUPipelineLayout.bindGroupLayouts A, B, C 创建。 GPUComputePipeline 对象 Y 是由 GPUPipelineLayout.bindGroupLayouts A, D, C 创建。 假设命令编码序列有两个调度:
  1. setBindGroup(0, ...)

  2. setBindGroup(1, ...)

  3. setBindGroup(2, ...)

  4. setPipeline(X)

  5. dispatch()

  6. setBindGroup(1, ...)

  7. setPipeline(Y)

  8. dispatch()

在这种情况下,用户代理将不得不重新绑定组插槽 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 的描述。

返回: GPUPipelineLayout

  1. 如果以下任一条件为满足:

    设定 limitsthis.[[device]].[[limits]]

    allEntries 是连接 descriptor.bindGroupLayouts 中所有 bglbgl.[[descriptor]].entries 的结果。

    Then:

    1. 在当前范围内产生一个带有适当错误消息的GPUValidationError

    2. 创建一个新的 invalid GPUPipelineLayout 并返回结果。

  2. 设定 pl 为一个新的 GPUPipelineLayout 对象。

  3. 设定 pl.[[bindGroupLayouts]]descriptor.bindGroupLayouts

  4. 返回 pl

注意:两个 GPUPipelineLayout 对象对于任何用法都被认为是等效的 如果它们的内部 [[bindGroupLayouts]] 序列包含 GPUBindGroupLayout 对象是 group-equivalent

8.4. Example

创建一个描述uniform buffer捆绑,纹理,采样器的 GPUBindGroupLayout,之后使用 GPUBindGroupLayout 创建 GPUBindGroupGPUPipelineLayout
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();但应该只是省略 hintsGPUShaderModuleCompilationHint 中的未知信息。省略此信息可能会导致编译推迟到 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()算法步骤。

使用 WGSL 代码创建 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

从着色器codelineNum行的开头到message对应的子字符串的点或开头的偏移量,以UTF-16代码单元为单位。值是one-based,这样linePos为1表示该行的第一个字符。

如果message对应于子字符串,则它指向子字符串的第一个UTF-16代码单元。如果消息不对应着色器代码中的任何特定点,则必须为0。

offset, of type unsigned long long, readonly

从UTF-16代码单元中的着色器code的开头到message对应的子字符串的点或开头的偏移量。必须引用与lineNumlinePos相同的位置。如果message不对应着色器code中的任何特定点,则必须为0。

length, of type unsigned long long, readonly

message对应的子字符串中UTF-16代码单元的数量。如果消息与子字符串不对应,则length必须为0。

注意:GPUCompilationMessage.lineNumGPUCompilationMessage.linePos是one-based,因为它们最常见的用途是打印人类可读的消息,这些消息可以与许多文本编辑器中显示的行号和列号相关联。

注意:GPUCompilationMessage.offsetGPUCompilationMessage.length适合传递给 substr() 以检索message对应的着色器code的子字符串。

compilationInfo()

返回GPUShaderModule编译时产生的任何消息。

消息的位置、顺序和内容是实现定义的。特别是,消息可能不会按 lineNum 排序。

Called on: GPUShaderModule this.

Returns: Promise<GPUCompilationInfo>

问题:描述compilationInfo()算法步骤。

10. 管道

一个 管线,无论是 GPUComputePipeline 还是 GPURenderPipeline, 表示由 GPU 硬件、驱动程序、 和用户代理,以绑定和顶点缓冲区的形式处理输入数据, 并产生一些输出,如输出渲染目标中的颜色。

在结构上,pipeline 由一系列可编程阶段(着色器)组成 和固定功能状态,例如混合模式。

注意:在内部,取决于目标平台, 驱动程序可能会将一些固定功能状态转换为着色器代码, 并将其与用户提供的着色器链接在一起。 这种链接是将对象作为一个整体创建的原因之一。

此组合状态创建为单个对象 (通过 GPUDevice.createComputePipeline()GPUDevice.createRenderPipeline()), 并切换为一个 (相应地通过 GPUComputePassEncoder.setPipelineGPURenderEncoderBase.setPipeline)。

10.1. 基础管道

dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
    GPUPipelineLayout layout;
};

interface mixin GPUPipelineBase {
    GPUBindGroupLayout getBindGroupLayout(unsigned long index);
};

GPUPipelineBase 有以下内部插槽:

[[layout]] of type GPUPipelineLayout.

可以与 this 一起使用的资源布局的定义.

GPUPipelineBase 有以下方法:

getBindGroupLayout(index)

获取一个 GPUBindGroupLayout,它与 index 处的 GPUPipelineBaseGPUBindGroupLayout 兼容。

调用: GPUPipelineBase this.

参数:

Arguments for the GPUPipelineBase.getBindGroupLayout(index) method.
Parameter Type Nullable Optional Description
index unsigned long 对管道布局的 [[bindGroupLayouts]] 序列的索引。

返回: GPUBindGroupLayout

  1. 如果 indexthis.[[device]].[[limits]].maxBindGroups:

    1. 抛出一个 RangeError.

  2. 如果 this 不是 valid:

    1. 返回一个新的错误的 GPUBindGroupLayout.

  3. 返回一个新的 GPUBindGroupLayout 对象引用相同的内部对象 this.[[layout]].[[bindGroupLayouts]][index].

问题:一旦我们拥有 GPUBindGroupLayout 的内部对象,请更正确地指定此项。 或者,只有规范作为 group-equivalent 的新内部对象

注意:仅返回新的 GPUBindGroupLayout 对象可确保 Content timelineDevice timeline 之间不需要同步。

10.1.1. 默认管道布局

在没有 layout 的情况下创建的 GPUPipelineBase 对象具有创建和使用的默认布局。

要为 GPUPipelineBase pipeline 创建 default pipeline layout, 运行以下步骤:

  1. groupDescs 是一系列 device.[[limits]].maxBindGroups 新的 GPUBindGroupLayoutDescriptor 对象。

  2. 对于每个在 groupDescs 中的 groupDesc:

    1. 设置 groupDesc.entries 为一个空序列。

  3. 对于每个 GPUProgrammableStage stageDesc 在用于创建 pipeline 的描述符中:

    1. stageInfostageDesc 的“反射信息”。

      问题:定义反射信息概念,以便此规范可以与 WGSL 规范接口,并获取特定入口点的 GPUShaderModule 接口的信息。

    2. shaderStage 成为 stageDesc.modulestageDesc.entryPointGPUShaderStageFlags

    3. 对于每个资源 resourcestageInfo 的资源接口中:

      1. group 成为 resource 的 “group” 装饰。

      2. binding 成为 resource 的 "binding" 装饰。

      3. entry 成为一个新的 GPUBindGroupLayoutEntry.

      4. 设定 entry.bindingbinding.

      5. 设定 entry.visibilityshaderStage.

      6. 如果 resource 用于采样器绑定:

        1. samplerLayout 成为一个新的 GPUSamplerBindingLayout.

        2. 设置 entry.samplersamplerLayout.

      7. 如果 resource 用于比较采样器绑定:

        1. samplerLayout 成为一个新的 GPUSamplerBindingLayout.

        2. 设置 samplerLayout.type"comparison".

        3. 设置 entry.samplersamplerLayout.

      8. 如果 resource 用于缓冲区绑定:

        1. bufferLayout 成为一个新的 GPUBufferBindingLayout.

        2. 设置 bufferLayout.minBindingSizeresource 的缓冲区绑定大小的最小值.

          问题:链接到“反射信息”中“最小缓冲区绑定大小”的定义。

        3. 如果 resource 用于只读存储缓冲区:

          1. 设定 bufferLayout.type"read-only-storage".

        4. 如果 resource 用于存储缓冲区:

          1. 设置 bufferLayout.type"storage".

        5. 设置 entry.bufferbufferLayout.

      9. 如果 resource 用于采样纹理绑定:

        1. 设置 textureLayout 为一个新的 GPUTextureBindingLayout.

        2. 如果 resource 用于深度采样纹理绑定:

          如果 resource 的采样类型是:

        3. 设置 textureLayout.viewDimensionresource 的维度。

        4. 如果 resource 用于多重采样纹理:

          1. 设置 textureLayout.multisampledtrue.

        5. 设置 entry.texturetextureLayout.

      10. 如果 resource 用于存储纹理绑定:

        1. storageTextureLayout 成为一个新的 GPUStorageTextureBindingLayout

        2. 设置 storageTextureLayout.formatresource 的格式。

        3. 设置 storageTextureLayout.viewDimensionresource 的维度。

        4. 如果 resource 用于只写存储纹理:

          1. 设置 storageTextureLayout.access"write-only"

        5. 设置 entry.storageTexturestorageTextureLayout

      11. 如果 groupDescs[group] 有一个条目 previousEntry binding 等于 binding

        1. 如果 entry 具有与 previousEntry 不同的 visibility:

          1. entry.visibility 中设置的位添加到 previousEntry.visibility

        2. 如果 resource 用于缓冲区绑定和 entry 有比 previousEntry 更大的 buffer.minBindingSize:

          1. 设置 previousEntry.buffer.minBindingSizeentry.buffer.minBindingSize

        3. 如果 resource 是一个采样的纹理绑定和 entry 具有与 previousEntry 不同的 texture.sampleType 并且两者 entrypreviousEntrytexture.sampleType"float""unfilterable-float"

          1. 设置 previousEntry.texture.sampleType"float".

        4. 如果任何其他属性在 entry 之间不相等 和 previousEntry:

          1. 返回 null(这将导致管道的创建失败)。

      12. 其他

        1. 附加 entrygroupDescs[group]。

  4. groupLayouts 成为一个新的序列。

  5. 对于每一个在 groupDescs 中的 groupDesc:

    1. bindGroupLayout 成为调用 device.createBindGroupLayout()(groupDesc) 的结果。

    2. 设置 bindGroupLayout.[[exclusivePipeline]]pipeline

    3. 附加 bindGroupLayoutgroupLayouts

  6. desc 成为一个新的 GPUPipelineLayoutDescriptor

  7. 设置 desc.bindGroupLayoutsgroupLayouts

  8. 返回 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>

指定着色器模块 modulepipeline-overridable 常量的值。

每个这样的 pipeline-overridable 常量都由单个 [=pipeline-overridable constant identifier string==] 唯一标识(表示常量的数字 ID,如果指定了一个,否则表示常量的标识符名称)。

每个键值对的键必须等于一个这样的常量的标识符字符串。 执行管道时,该常量将具有指定的值。

值被指定为 GPUPipelineConstantValue,它是一个 double, 它被转换为相应管道可覆盖常量的 WGSL 数据类型(booli32u32、 或 f32) 通过 [=converted to an IDL value|an IDL value=|一个 IDL 值=] booleanlongunsigned longfloat)。

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"
    }
}
validating GPUProgrammableStage(stage, descriptor, layout)

参数:

如果满足以下所有条件,则返回 true

返回值 false 对应于 pipeline-creation error

validating shader binding(binding, layout)

参数:

bindGroup 是绑定组索引,和 bindIndex 是着色器绑定声明 variable 的绑定索引。

如果满足以下所有条件,则返回 true

资源绑定被视为由着色器入口点statically used 当且仅当着色器模块的控制流图可以访问它,从入口点开始。

10.2. GPUComputePipeline

GPUComputePipeline 是一种 pipeline 控制计算着色器阶段, 并且可以在 GPUComputePassEncoder 中使用。

计算输入和输出都包含在绑定中, 根据给定的 GPUPipelineLayout。 输出对应于类型为 "storage"buffer 绑定 和 storageTexture 绑定类型为 "write-only"

计算 pipeline 的阶段:

  1. 计算着色器

[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.

返回: GPUComputePipeline

  1. pipeline 成一个新的有效的 GPUComputePipeline 对象.

  2. thisDevice timeline 上发出以下步骤:

    1. 如果不满足以下任一条件:

      Then:

      1. 在当前范围内产生一个带有适当错误信息的GPUValidationError

      2. 使 pipeline invalid.

    2. 如果 descriptor.layoutundefined:

      1. pipeline 设置 pipeline.[[layout]] 为一个新的 default pipeline layout

      否则设置pipeline.[[layout]]descriptor.layout

  3. 返回 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>

  1. promisea new promise.

  2. thisDevice timeline 上发出以下步骤:

    1. pipeline 是一个新的 GPUComputePipeline,就像 this 一样。 createComputePipeline() 是用 descriptor 调用的;

    2. pipeline 已准备好使用,resolve promisepipeline

  3. 返回 promise.

创建一个简单的 GPUComputePipeline:
const computePipeline = gpuDevice.createComputePipeline({
    layout: pipelineLayout,
    compute: {
        module: computeShaderModule,
        entryPoint: 'computeMain',
    }
});

10.3. GPURenderPipeline

GPURenderPipeline 是一种控制顶点和片段着色器阶段的 pipeline, 可以在 GPURenderPassEncoder 以及 GPURenderBundleEncoder 中使用。

渲染 pipeline 输入是:

渲染 pipeline 输出是:

渲染 pipeline 由以下 render stages组成:

  1. 顶点获取,由GPUVertexState.buffers控制

  2. 顶点着色器,由GPUVertexState控制

  3. 原始组装,由GPUPrimitiveState控制

  4. 光栅化,由GPUPrimitiveStateGPUDepthStencilStateGPUMultisampleState控制

  5. 片段着色器,由GPUFragmentState控制

  6. Stencil 测试和操作,由 GPUDepthStencilState 控制

  7. 深度测试和写入,由GPUDepthStencilState控制

  8. 输出合并,由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 渲染

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.

返回: GPURenderPipeline

  1. pipeline 为一个新的可用的 GPURenderPipeline 对象。

  2. thisDevice timeline 上发出以下步骤:

    1. 如果不满足以下任一条件:

      Then:

      1. 在当前范围内产生一个带有适当错误信息的GPUValidationError

      2. 使 pipeline invalid

    2. 设置 pipeline.[[descriptor]]descriptor

    3. 设置 pipeline.[[writesDepth]] 为 false.

    4. 设置 pipeline.[[writesStencil]] 为 false.

    5. depthStencildescriptor.depthStencil.

    6. 如果 depthStencil 不是 null:

      1. 设置 pipeline.[[writesDepth]]depthStencil.depthWriteEnabled.

      2. 如果 depthStencil.stencilWriteMask 不是 0:

        1. stencilFrontdepthStencil.stencilFront.

        2. stencilBackdepthStencil.stencilBack.

        3. cullModedescriptor.primitive.cullMode.

        4. 如果 cullMode 不是 "front", 并且 stencilFront.passOp, stencilFront.depthFailOp, 或 stencilFront.failOp 其中之一不是 "keep":

          1. 设置 pipeline.[[writesStencil]] 为 true.

        5. 如果 cullMode 不是 "back", 并且 stencilBack.passOp, stencilBack.depthFailOp, 或 stencilBack.failOp 其中之一不是 "keep":

          1. 设置 pipeline.[[writesStencil]] 为 true.

    7. 如果 descriptor.layoutundefined:

      1. pipeline 设置 pipeline.[[layout]] 为一个新的 default pipeline layout

      否则设置 pipeline.[[layout]]descriptor.layout.

  3. 返回 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>

  1. promisea new promise.

  2. thisdevice timeline 上发出以下步骤:

    1. pipeline 是一个新创建的 GPURenderPipeline, 就好像 this.createRenderPipeline() 是用 descriptor 调用的一样;

    2. pipeline 已准备好使用, 用 pipeline resolve promise

  3. 返回 promise.

validating GPURenderPipelineDescriptor(descriptor, device) 参数:

如果满足以下所有条件,则返回 true

问题:我们应该验证点和线的 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 topology = "triangle-list";
    GPUIndexFormat stripIndexFormat;
    GPUFrontFace frontFace = "ccw";
    GPUCullMode cullMode = "none";

    // Requires "depth-clip-control" feature.
    boolean unclippedDepth = false;
};
validating GPUPrimitiveState(descriptor, features) 参数:

如果满足以下所有条件,则返回 true

enum GPUFrontFace {
    "ccw",
    "cw",
};
enum GPUCullMode {
    "none",
    "front",
    "back",
};

10.3.3. 多重采样状态

dictionary GPUMultisampleState {
    GPUSize32 count = 1;
    GPUSampleMask mask = 0xFFFFFFFF;
    boolean alphaToCoverageEnabled = false;
};
validating GPUMultisampleState(descriptor) 参数:

如果满足以下所有条件,则返回 true:

10.3.4. 片段状态

dictionary GPUFragmentState : GPUProgrammableStage {
    required sequence<GPUColorTargetState> targets;
};
validating GPUFragmentState(descriptor) 如果满足以下所有要求,则返回 true
component 如果满足以下要求,则是 valid GPUBlendComponent

问题:定义 GPUProgrammableStage 的“静态使用”事物的范围

10.3.5. 颜色目标状态

dictionary GPUColorTargetState {
    required GPUTextureFormat format;

    GPUBlendState blend;
    GPUColorWriteFlags writeMask = 0xF;  // GPUColorWrite.ALL
};
dictionary GPUBlendState {
    required GPUBlendComponent color;
    required GPUBlendComponent alpha;
};
typedef [EnforceRange] unsigned long GPUColorWriteFlags;
[Exposed=(Window, DedicatedWorker)]
namespace GPUColorWrite {
    const GPUFlagsConstant RED   = 0x1;
    const GPUFlagsConstant GREEN = 0x2;
    const GPUFlagsConstant BLUE  = 0x4;
    const GPUFlagsConstant ALPHA = 0x8;
    const GPUFlagsConstant ALL   = 0xF;
};
10.3.5.1. 混合状态
dictionary GPUBlendComponent {
    GPUBlendOperation operation = "add";
    GPUBlendFactor srcFactor = "one";
    GPUBlendFactor dstFactor = "zero";
};
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 depthCompare = "always";

    GPUStencilFaceState stencilFront = {};
    GPUStencilFaceState stencilBack = {};

    GPUStencilValue stencilReadMask = 0xFFFFFFFF;
    GPUStencilValue stencilWriteMask = 0xFFFFFFFF;

    GPUDepthBias depthBias = 0;
    float depthBiasSlopeScale = 0;
    float depthBiasClamp = 0;
};
dictionary GPUStencilFaceState {
    GPUCompareFunction compare = "always";
    GPUStencilOperation failOp = "keep";
    GPUStencilOperation depthFailOp = "keep";
    GPUStencilOperation passOp = "keep";
};
enum GPUStencilOperation {
    "keep",
    "zero",
    "replace",
    "invert",
    "increment-clamp",
    "decrement-clamp",
    "increment-wrap",
    "decrement-wrap",
};
validating GPUDepthStencilState(descriptor) 参数:

返回 true,当且仅当满足以下所有条件:

问题:该算法如何支持在扩展中添加的深度/模板格式?

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

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 stepMode = "vertex";
    required sequence<GPUVertexAttribute> attributes;
};
dictionary GPUVertexAttribute {
    required GPUVertexFormat format;
    required GPUSize64 offset;

    required GPUIndex32 shaderLocation;
};
validating GPUVertexBufferLayout(device, descriptor, vertexStage) 参数:

返回 true,当且仅当满足以下所有条件:

validating GPUVertexState(device, descriptor) 参数:

返回 true,当且仅当满足以下所有条件:

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 commandlist会在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 commandslist 将在 Queue Timeline 上执行。

编码器状态可能是以下之一:

"open"

编码器可用于对新命令进行编码。

"locked"

无法使用编码器,因为它被子编码器锁定:它是一个 GPUCommandEncoder,并且一个 GPURenderPassEncoderGPUComputePassEncoder 处于活动状态。当传递结束时,编码器再次变为“打开”。

在此状态下发出的任何命令都会使编码器invalid

"ended"

编码器已结束,无法再对新命令进行编码。

在此状态下发出的任何命令都会生成 GPUValidationError

To Prepare the encoder state of 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

thisDevice timeline上发起以下步骤:

  1. 使pass为一个新的GPURenderPassEncoder对象。

  2. 如果以下任何条件没有满足,产生一个校验错误并停止。

  3. 设置this.[[state]]为"locked"。

  4. 对每个descriptor.colorAttachments中的colorAttachment:

    1. colorAttachment.view看到的texture subresource被视为在渲染通道期间用作attachment

  5. 设置depthStencilAttachmentdescriptor.depthStencilAttachment

  6. 如果depthStencilAttachment不是 null:

    1. 设置depthStencilViewdepthStencilAttachment.view

    2. 如果depthStencilAttachment.depthReadOnlystencilReadOnly设置了值:

      1. depthStencilView看到的texture subresource被视为在渲染通道期间用作attachment-read

      问题:用“一组子资源”算法来描述此算法。

    3. 否则, depthStencilView看到的texture subresource被视为在渲染通道期间用作attachment

    4. 设置pass.[[depthReadOnly]]depthStencilAttachment.depthReadOnly

    5. 设置pass.[[stencilReadOnly]]depthStencilAttachment.stencilReadOnly

  7. 设置pass.[[layout]]derive render targets layout from pass(descriptor)。

  8. 对每个descriptor.timestampWrites中的timestampWrite,

    1. 如果timestampWrite.location"beginning", 添加(Append)一个GPU commandpass.[[command_encoder]].[[commands]],将GPU时间戳值写入timestampWrite.querySettimestampWrite.queryIndex索引处。

    2. 否则,timestampWrite.location"end",添加timestampWritepass.[[endTimestampWrites]]

  9. 问题:入队附件加载/清除。

  10. 返回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

thisDevice timeline上发起如下步骤:

  1. 如果以下任何条件没有满足,产生一个校验错误并停止。

  2. 设置this.[[state]]为"locked"。

  3. 设置pass为一个新的GPUComputePassEncoder对象。

  4. 对每个descriptor.timestampWrites中的timestampWrite

    1. 如果timestampWrite.location"beginning", 添加(Append一个GPU commandpass.[[command_encoder]].[[commands]],将GPU时间戳值写入timestampWrite.querySet中的timestampWrite.queryIndex索引处。 index in timestampWrite.querySet.

    2. 否则,Otherwise, 如果timestampWrite.location"end",则添加(AppendtimestampWritepass.[[endTimestampWrites]]

  5. 返回pass

12.4. 拷贝命令

问题:这些字典定义应该在图像副本部分内。

12.4.1. GPUImageDataLayout

dictionary GPUImageDataLayout {
    GPUSize64 offset = 0;
    GPUSize32 bytesPerRow;
    GPUSize32 rowsPerImage;
};

GPUImageDataLayout是一些线性内存中的图像(images)布局。它在texturebuffer之间复制数据时使用,或者在调度GPUQueuetexture写入时使用。

问题:更精确地定义图像,特别地,将它们定义为由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;
};
validating GPUImageCopyBuffer

Arguments:

Returns: boolean

当且仅当所有以下条件都满足时,返回 true

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 to 0

要复制到/从的texture的Mip-map级别。

origin, of type GPUOrigin3D, defaulting to {}

定义复制的原点 - 要复制到/从的纹理子区域的最小角。与 copySize 一起定义完整复制子区域。

aspect, of type GPUTextureAspect, defaulting to "all"

定义要复制到/从纹理的宽高比。

validating GPUImageCopyTexture

Arguments:

Returns: boolean

使:

当且仅当以下所有条件都满足时,返回 true

问题(gpuweb/gpuweb#69):使用1d3d纹理定义副本。

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 to false

描述写入纹理的数据是否应将其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 to false

描述源图像是否垂直翻转。

如果此选项设置为 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 上发出以下步骤:

  1. 准备this的编码器状态(Prepare the encoder state)。如果返回 false,则停止。

  2. 如果不满足以下任何条件,则产生一个校验错误并停止。

    • this.[[state]]open状态。

    • source可以和this一起有效使用。

    • destination可以和this一起有效使用。

    • source.[[usage]]包含COPY_SRC

    • destination.[[usage]]包含COPY_DST

    • size是4的倍数。

    • sourceOffset是4的倍数。

    • destinationOffset是4的倍数。

    • (sourceOffset + size)不会溢出GPUSize64

    • (destinationOffset + size)不会溢出GPUSize64

    • source.[[size]]大于等于(sourceOffset + size)。

    • destination.[[size]]大于等于(destinationOffset + size)。

    • sourcedestination不是同一个GPUBuffer

    问题(gpuweb/gpuweb#69):指出如何处理规范中的溢出。

  3. 问题:描述 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上发起以下步骤:

  1. 准备this的编码器状态(Prepare the encoder state)。如果返回 false,则停止。

  2. 如果size缺失, 设置sizemax(0, |buffer|.{{GPUBuffer/[[size]]}} - |offset|)

  3. 如果以下任何条件未满足,生成一个校验错误并停止。

12.4.8. Image Copies

WebGPU提供copyBufferToTexture()以buffer-to-texture拷贝,copyTextureToBuffer() 以texture-to-buffer拷贝,以及writeTexture()以ArrayBuffer-to-texture写入。

以下定义和校验规则对这些方法以及copyTextureToTexture()都应用。

问题:术语“图像拷贝”包括copyTextureToTexture么?

imageCopyTexture subresource sizevalid texture copy range同样对 copyTextureToTexture()应用。

imageCopyTexture subresource size

Arguments:

Returns: GPUExtent3D

imageCopyTextureimageCopyTexture subresource size计算如下:

它的width, heightdepthOrArrayLayers分别为=mipmap level=] imageCopyTexture.mipLevel上的imageCopyTexture.texture subresource physical size的宽度,高度,和深度。

问题:将此定义为具有 (texture, mipmapLevel) 参数的算法,并使用调用语法而不是通过标签引用定义。

校验线性纹理数据(validating linear texture data(layout, byteSize, format, copyExtent))

Arguments:

GPUImageDataLayout layout

线性纹理数据的布局。

GPUSize64 byteSize

显性数据的总大小,以字节为单位。

GPUTextureFormat format

纹理格式。

GPUExtent3D copyExtent

要复制的纹理的范围。

  1. 使blockWidth, blockHeight, and blockSize格式texel block widthheight,和size

  2. 假设copyExtent.widthblockWidth的倍数并且copyExtent.heightblockHeight的倍数。使:

    • widthInBlockscopyExtent.width ÷ blockWidth.

    • heightInBlockscopyExtent.height ÷ blockHeight.

    • bytesInLastRowblockSize × widthInBlocks.

  3. 如果以下条件未满足则失败:

  4. 使requiredBytesInCopy为0。

  5. 如果copyExtent|.depthOrArrayLayers > 1:

    1. 使bytesPerImagelayout.bytesPerRow × layout.rowsPerImage

    2. 使bytesBeforeLastImagebytesPerImage × (copyExtent.depthOrArrayLayers − 1)。

    3. bytesBeforeLastImage加至requiredBytesInCopy

  6. 如果copyExtent.depthOrArrayLayers > 0:

    1. 如果heightInBlocks > 1, 将 layout.bytesPerRow × (heightInBlocks − 1) 加至requiredBytesInCopy

    2. 如果heightInBlocks > 0, 将 bytesInLastRow加至requiredBytesInCopy

  7. 如果以下条件未满足则失败:

    • layout.offset + requiredBytesInCopybyteSize

Valid Texture Copy Range

给定一个 GPUImageCopyTexture imageCopyTexture 和一个 GPUExtent3D copySize, 使

应用以下校验:

问题(gpuweb/gpuweb#69): 使用 1d3d 纹理定义副本

问题(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 上发出以下步骤:

  1. 准备this的编码器状态(Prepare the encoder state。如果返回 false,则停止。

  2. 如果以下任何条件未满足,则生成一个校验错误并停止。

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 上发出以下步骤:

  1. 准备this的编码器状态。如果返回false,则停止。

  2. 如果以下任何条件未满足,产生一个校验错误并停止。

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 上发出以下步骤:

  1. 准备this的编码器状态。如果返回 false,则停止。

  2. 如果以下任何条件未满足,生成一个校验错误并停止。

Two GPUTextureFormats format1 and format2 are copy-compatible if:

问题(gpuweb/gpuweb#2322): 一旦 viewFormats 中允许更多格式,考虑在 viewFormats 中有任何重叠时使两个纹理副本兼容.

The set of subresources for texture copy(imageCopyTexture, copySize) 是一个包含如下内容的集合:

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

  1. 如果this.[[device]].[[features]]不为contain "timestamp-query",抛出一个TypeError

  2. this.[[device]]Device Timeline 上发出以下步骤:

    1. 准备this的编码器状态。如果返回 false,则停止。

    2. 如果以下任何条件未满足,生成一个校验错误并停止。

    问题: 描述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 上发出以下步骤:

  1. 准备this的编码器状态。如果返回 false,则停止。

  2. 如果以下任何条件未满足,生成一个GPUValidationError并停止。

    问题: 描述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

  1. 使commandBuffer为一个新的GPUCommandBuffer

  2. thisDevice timeline上发起如下步骤:

    1. 如果以下条件都满足则使 validationFailedtrue,否则为 false

    2. 设置 this.[[state]] 为 "ended".

    3. 如果 validationFailedfalse, 则:

      1. 在当前范围内生成一个带有适当错误消息的GPUValidationError

      2. 返回一个新的invalid GPUCommandBuffer

    4. 设置this.[[state]]closed

    5. 设置commandBuffer.[[command_list]]this.[[commands]]

  3. 返回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 type GPUCommandEncoder.

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 发布一下步骤 :

  1. 如果不满足以下任一条件,则使 this invalid 并停止。

  2. 设置 this.[[bind_groups]][indexbindGroup.

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

  1. 如果未满足以下任何要求,则抛出 RangeError 并停止。

    • dynamicOffsetsDataStart 必须 ≥ 0.

    • dynamicOffsetsDataStart + dynamicOffsetsDataLength 必须 ≤ dynamicOffsetsData.length.

  2. dynamicOffsets 成为一个 list 包含一个范围, 从获取缓冲区源的副本dynamicOffsetsData 的元素 dynamicOffsetsDataLength 的索引 dynamicOffsetsDataStart 开始。

  3. 调用 this.setBindGroup(index, bindGroup, dynamicOffsets)。

迭代给定GPUBindGroup中的每个动态绑定偏移 bindGroup 使用给定的 steps 为每个动态偏移执行:
  1. dynamicOffsetIndex0

  2. layoutbindGroup.[[layout]]

  3. 对于每个 bindGroup.[[entries]] 中的 GPUBindGroupEntry entry:

    1. bindingDescriptor 成为 GPUBindGroupLayoutEntrylayout.[[entryMap]][entry.binding]:

    2. 如果 bindingDescriptor.buffer 不是 undefined 并且 bindingDescriptor.buffer.hasDynamicOffsettrue:

      1. bufferBindingentry.resource

      2. bufferLayoutbindingDescriptor.buffer

      3. 调用 steps 使用 bufferBindingbufferLayout,和 dynamicOffsetIndex

      4. dynamicOffsetIndexdynamicOffsetIndex + 1

Validate encoder bind groups(encoder, pipeline)

参数:

GPUProgrammablePassEncoder encoder

正在验证绑定组的编码器。

GPUPipelineBase pipeline

用于验证 encoders 绑定组是否兼容的管道。

  1. 如果不满足以下任何一个条件,则返回 false:

    问题:对未使用 minBindingSize 预先验证的缓冲区绑定添加验证,绑定范围足以满足着色器的最小绑定大小要求。

  2. Encoder bind groups alias a writable resource(encoder, pipeline) 必须为 false.

    问题(gpuweb/gpuweb#1842): 确定当应用程序违反此规则时会发生什么。 它是验证错误,多种可能行为之一,还是我们只是完全删除此限制并允许可写绑定以未定义结果为别名?

否则返回 true

如果任何可写缓冲区绑定范围与同一缓冲区的任何其他绑定范围重叠,或者任何可写纹理绑定在 texture subresources 中与任何其他纹理绑定(可能使用相同或不同的 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.

  1. 对每个 [VERTEX, FRAGMENT, COMPUTE] 中的 stage:

    1. 使 bufferBindings 为 (GPUBufferBinding 中的 list, boolean) 对,其中后者指资源是否可写入。

    2. 对每个 pipeline.[[layout]].[[bindGroupLayouts]] 中的 (GPUIndex32 index, GPUBindGroupLayout bindGroupLayout) 对:

      1. 使 bindGroupEntriesencoder.[[bind_groups]][index].entries.

      2. 使 bindGroupLayoutEntriesbindGroupLayout.[[descriptor]].entries.

      3. 对每个 bindGroupLayoutEntries 中的 GPUBindGroupEntry bindGroupLayoutEntry: 对包含 stagebindGroupLayoutEntry.visibility

        1. 使 bindGroupEntrybindGroupEntries 中的 GPUBindGroupEntry,其 bindGroupEntry.binding 等于 bindGroupLayoutEntry.binding

        2. 如果 bindGroupEntry.resourceGPUBufferBinding:

          1. 使 GPUBufferBinding resourcebindGroupEntry.resource.

          2. 使 resourceWritable 为 (bindGroupLayoutEntry.buffer.type == "storage").

          3. 对每个 bufferBindings 中的 (GPUBufferBinding pastResource, boolean pastResourceWritable) 对:

            1. 如果 (resourceWritable or pastResourceWritable) 为真, 及 pastResourceresourcebuffer-binding-aliasing, 返回 true.

          4. Append ([resource], resourceWritable) 至 bufferBindings.

          否则,如果 bindGroupEntry.resourceGPUTextureView

          1. 使 GPUTextureView resourcebindGroupEntry.resource.

          2. 使 resourceWritable 为 (bindGroupLayoutEntry.storageTexture.access == "write-only").

          3. 如果 bindGroupLayoutEntry.storageTexturenull, 则继续.

          4. 对每个 textureViews 中的 (GPUTextureView pastResource, boolean pastResourceWritable) 对,

            1. 如果 (resourceWritable or pastResourceWritable) 为真, 及 pastResourceresourcetexture-view-aliasing, 返回 true.

          5. Append ([resource], resourceWritable) 至 textureViews.

          否则,继续。

  2. Return false.

14. 调试标记

GPUDebugCommandsMixin 提供了将调试标签应用于命令组或将单个标签插入命令序列的方法。

调试组可以嵌套以创建标记命令的层次结构,并且必须很好地平衡。

object labels 一样,这些标签没有必需的行为,但可能会显示在错误消息和浏览器开发人员工具中,并且可能会传递给原生 API 后端。

interface mixin GPUDebugCommandsMixin {
    undefined pushDebugGroup(USVString groupLabel);
    undefined popDebugGroup();
    undefined insertDebugMarker(USVString markerLabel);
};

GPUDebugCommandsMixin 仅包含在包含 GPUObjectBaseGPUCommandsMixin 的接口中。

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 上发出以下步骤:

  1. 准备this的编码器状态(Prepare the encoder state)。如果返回false,则停止。

  2. this.[[debug_group_stack]]Push groupLabel

popDebugGroup()

结束最近由 pushDebugGroup() 启动的标记调试组。

Called on: GPUDebugCommandsMixin this.

Returns: undefined

this.[[device]]Device Timeline 上发出以下步骤:

  1. 准备this的编码器状态(Prepare the encoder state)。如果为false,则停止。

  2. 如果不满足以下任何要求,则使 this 无效,然后停止。

  3. 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 上发出以下步骤:

  1. 准备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 type GPUComputePipeline

当前GPUComputePipeline,初始为 null

[[endTimestampWrites]], of type GPUComputePassTimestampWrites

通道结束时需要被执行的时间戳附件。

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.

Valid Usage

Given a GPUComputePassDescriptor this the following validation rules apply:

  1. For each timestampWrite in this.timestampWrites:

    1. timestampWrite.querySet.[[descriptor]].type is "timestamp".

    2. 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上发起以下步骤:

  1. 如果以下任何条件未满足,使this invalid并且停止。

    • pipeline可以和this一起有效使用。

  2. 设置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上发起以下步骤:

  1. 如果以下任何条件未满足,使this invalid并停止。

  2. 使passState为一个this|的快照当前状态。

  3. Append 一个 GPU commandthis.[[commands]],执行以下 queue timeline 步骤:

    1. 使用 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]