区块链技术博客
www.b2bchain.cn

WebGPU 规范篇 06 资源及其打组绑定求职学习资料

本文介绍了WebGPU 规范篇 06 资源及其打组绑定求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

系列博客目录传送门:https://xiaozhuanlan.com/topic/9587342601

  • 1 关系简易图解
  • 2 资源绑定组 GPUBindGroup
    • 如何创建
    • GPUBindGroupEntry 类型
      • GPUBindingResource
      • GPUBufferBinding
    • 译者注
    • 举例
      • ① 采样器资源
      • ② 纹理(视图)资源
      • ③ GPUBuffer 资源
    • 创建要遵守的规则
  • 3 资源绑定组的布局 GPUBindGroupLayout
    • 如何创建
      • GPUBindGroupLayoutEntry 类型
      • 描述缓存对象:GPUBufferBindingLayout
      • 描述采样器对象:GPUSamplerBindingLayout


资源绑定,即 JavaScript 中(即 CPU 端)如何对待传递到 GPU 的数据进行组织、分配的一种设计。

为了完成这个过程(CPU到GPU),WebGPU 设计了几个对象用于管理这些数据,这些数据包括 某些GPUBuffer(例如UBO,但是不包括VBO)、GPUTexture、GPUSampler、存储型纹理、外部纹理五种,这几个对象是:

  • 资源绑定组(以后均简称绑定组)- GPUBindGroup
  • 资源绑定组布局(以后称为绑定组的布局对象)- GPUBindGroupLayout
  • 管线布局 – GPUPipelineLayout

和规范中顺序略有不同,我按我上面这个来。

1 关系简易图解

     GPUBindGroup <--- 1 ---┓                动区                     GPUBindGroupLayout   ----------- GPUPipelineLayout <--- N ---┛                静区     |     1     ↓ GPUPipelineBase

简单的说就是绑定组有其布局,管线也有其布局;

绑定组的布局负责告诉资源长什么样子,管线的布局告诉管线着色器里头有多少类和分别有多少个资源坑位要进来;

两个布局负责沟通,那绑定组、管线就各司其职(一个负责组织管线所需的资源,一个负责某个渲染过程)。

2 资源绑定组 GPUBindGroup

资源绑定组,GPUBindGroup,一般会简单称之为“绑定组”,它组织了一些 资源,这些资源在某个具体的着色阶段一起起作用。

所谓的资源,就是 GPUBuffer、纹理、采样器等数据类型的对象。

如何创建

通过设备对象的 createBindGroup 方法创建,它需要一个必选的对象参数,这个对象参数要满足 GPUBindGroupDescriptor 类型。

dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {   required GPUBindGroupLayout layout;   required sequence<GPUBindGroupEntry> entries; };

看得出 GPUBindGroupDescriptor 类型需要两个必选参数:

  • 参数 layoutGPUBindGroupLayout 类型,通常称这个参数为资源绑定组的布局对象,有时候简单点就说对应的布局对象,下面会详细介绍这个类型;
  • 参数 entries,一个数组,每个元素皆为 GPUBindGroupEntry 类型,具体解释见下文。

GPUBindGroupEntry 类型

GPUBindGroupEntry 类型的对象,指代一种在着色阶段要用到的资源,包括一些简单的元数据。

这里的资源,在 WebGPU 中使用 GPUBindingResource 来定义。

dictionary GPUBindGroupEntry {   required GPUIndex32 binding;   required GPUBindingResource resource; };

GPUBindGroupEntry 对象的字段 binding 是一个 unsigned long 类型的数字,表示这个资源在着色器代码中的 location(在 WGSL 会介绍),即告诉着色器代码要从几号坑位取数据,一对一的。

而另一个字段 resource 自然指的就是这个下面要介绍的 GPUBindingResource 了。

GPUBindingResource

有四种 资源:采样器、纹理(视图)、缓存、外部纹理。

typedef (GPUSampler or GPUTextureView or GPUBufferBinding or GPUExternalTexture) GPUBindingResource;

常见的是前三种,第四种通常用于视频类型的纹理,有兴趣了解的读者可自行查阅纹理部分的章节。

第一种和第二种还比较好理解,在采样器和纹理章节能了解到如何创建,第三种并不是 GPUBuffer 的直接传递,而是嵌套了个对象,是 GPUBufferBinding 类型的,见下文:

GPUBufferBinding

dictionary GPUBufferBinding {   required GPUBuffer buffer;   GPUSize64 offset = 0;   GPUSize64 size; };

到这里就有熟悉的类型了,即 GPUBuffer

除此之外还有另外两个字段, offsetsize,前者默认值是 0,表示要从 GPUBuffer 的第几个字节开始,后者则为要从 GPUBuffer 的 offset 处向后取多少个字节。

译者注

通过 GPUBindGroup,明确地把一堆资源挨个(每个 entry)合并打包在一个组里,并且是按顺序(参数 binding)组织在一起。这就好比做菜时的食材,按顺序罗列在灶台边,做这道菜的是一组(绑定组),做另一道菜的是另一组(绑定组)。

举例

const bindGroup = device.createBindGroup({   layout: myBindGroupLayout, // 这个下面会介绍,这里假装已经有了   entries: [     /* ... */   ] })

① 采样器资源

entries: [   {     binding: 0,     resource: device.createSampler({ /* ... */ })   },   /* ... */ ]

② 纹理(视图)资源

entries: [   /* ... */,   {     binding: 1,     resource: myTexture.createView()   },   /* ... */ ]

③ GPUBuffer 资源

entries: [   /* ... */   {     binding: 2,     resource: {       buffer: uniformBuffer, // 通常通过绑定组传递的是 UBO,不绝对,       size: 16     }   } ]

创建要遵守的规则

  • descriptor.layout 字段必须是一个有效的布局对象
  • descriptor.layout 对象的 entries 数量必须与 descriptor.entries 的数量一致

对于每个 descriptor.entries 中的 GPUBindGroupEntry (此处以 bindEntry 指代)来说:

  • 此 bindEntry 的 binding 数字必须与 descriptor.layout 中的某一个一致,也即一一对应关系
  • 如果 descriptor.layout.entries 中的某个 GPUBindGroupLayoutEntry 对象:
    • 有 sampler 字段,那么 bindEntry.resource 就必须是一个有效的 GPUSampler,而且此 GPUBindGroupLayoutEntry 的 sampler 字段的 type 属性
    • "filtering",那么 bindEntry.resource 这个 GPUSampler 就不能是比较型采样器(即 isComparison 这个内部变量是 false);
    • "non-filering",那么 bindEntry.resource 这个 GPUSampler 既不能是比较型采样器,其 isFiltering 内部属性也不能是 true;
    • "comparison",那么 bindEntry.resource 这个 GPUSampler 就必须是比较型采样器(即 isComparison 内部属性是 true)
    • 有 texture 字段,那么 bindEntry.resource 必须是一个有效的 GPUTextureView,且此 GPUBindGroupLayoutEntry 的
    • texture 字段的 viewDimension 属性必须与 bindEntry.resource 这个 GPUTextureView 的 dimension 一致;
    • texture 字段的 sampleType 属性与 bindEntry.resource 这个 GPUTextureView 的 format 兼容;令 bindEntry.resource 这个 GPUTextureView 原本的纹理对象为 T,此时 T 的 usage 必须包括 "TEXTURE_BINDING"
    • texture 字段的 multisampled 属性是 true,那么上一条设定的纹理对象 T 的 sampleCount 必须大于1,否则 T.sampleCount 必须是 1.
    • 有 storageTexture 字段,那么 bindEntry.resource 必须是一个有效的 GPUTextureView 对象,此时令 T 为 bindEntry.resource 这个 GPUTextureView 对象原本的纹理对象:
    • 此 storageTexture 字段的 viewDimension 必须与 bindEntry.resource 这个 GPUTextureView 的 dimension 一致;
    • 此 storageTexture 字段的 format 必须与 bindEntry.resource 这个 GPUTextureView 的创建参数(GPUTextureViewDescriptor,创建完成后被内置,JavaScript 看不到)的 format 参数一致;
    • T 对象的 usage 必须包括 "STORAGE_BINDING"
    • 有 buffer 字段,那么 bindEntry.resource 必须是一个 GPUBufferBinding 对象,且 bindEntry.resource.buffer 必须是一个有效的 GPUBuffer 对象,不妨令这个 GPUBuffer 对象为 B 对象,且此 buffer 字段的 type 是:
    • "uniform",那么 B.usage 必须包括 "UNIFORM",且 bindEntry.resource.size 必须小于等于设备限制列表中的 maxUniformBufferBindingSize 值,bindEntry.resource.offset 必须是设备限制列表中 minUniformBufferOffsetAlignment 的倍数
    • "storage""read-only-storage",B.usage 必须包括 "STORAGE",且 bindEntry.resource.size 小于等于设备限制列表中的 maxStorageBufferBindingSize,bindEntry.resource.offset 必须是设备限制列表中的 minStorageBufferOffsetAlignment 的倍数

满足以上要求后,基本上绑定组对象就能创建成功,仍有一些可能不常用的细节需要读者自行查阅文档。

3 资源绑定组的布局 GPUBindGroupLayout

一个资源绑定组的布局对象,是 GPUBindGroupLayout 类型,简称绑定组的布局(对象),它的作用是联系与它配套的绑定组和对应阶段的着色器,告诉管线在什么着色阶段传入的数据长什么样子,是何种类。

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

如何创建

调用设备对象的 createBindGroupLayout 方法,即可创建一个绑定组布局对象。

此方法需要一个参数对象,需符合 GPUBindGroupLayoutDescriptor 类型:

dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {     required sequence<GPUBindGroupLayoutEntry> entries; };

它只有一个必选成员 entries,是一个数组,数组的每个元素是 GPUBindGroupLayoutEntry 类型的对象。

GPUBindGroupLayoutEntry 类型

GPUBindGroupLayoutEntry 描述一个在着色器中能被访问到的资源长什么样子,且如何找到它。

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,unsigned long 类型的数字,指定该 entry(也即资源)绑定号,绑定号在一个绑定组布局对象的 entries 数组所有元素中是唯一的,且必须和绑定组中的 entry 有对应,以便于在 WGSL 代码中访问对应资源;
  • 参数 visibilityGPUShaderStageFlags 类型,需从 GPUShaderStage 中访问枚举值,表示该 entry 在什么着色阶段可见,例如指定 visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,就意味着这个 entry 所描述的资源在顶点着色阶段和偏远着色阶段均可见。最后一个 COMPUTE 是计算管线的计算阶段。

还必须接受一个键值对作为此 entry 描述的资源的信息对象,需从 buffersamplertexturestorageTextureexternalTexture 中选一个。

描述缓存对象:GPUBufferBindingLayout

enum GPUBufferBindingType {   "uniform",   "storage",   "read-only-storage", };  dictionary GPUBufferBindingLayout {   GPUBufferBindingType type = "uniform";   boolean hasDynamicOffset = false;   GPUSize64 minBindingSize = 0; };

绑定组传递的 GPUBuffer 只有两种,UBO(即 "uniform" 类型的 GPUBuffer)和存储型 GPUBuffer,其中后者又分存储型("storage")和只读存储型("read-only-storage")两小种,通过 type 字段标识,默认值是 “uniform”,type 字段只能是 GPUBufferBindingType 枚举中的一个。

hasDynamicOffset 表示缓存对象是否有动态偏移值,默认是 false;

minBindingSize 表示的是被绑定的缓存对象的最小绑定大小,默认是 0(byte);

因为 type 的默认值是 “uniform”,所以如果你准备创建一个绑定组,并考虑到有 ubo 的传递,那么其实可以对某个 entry 简写成:

const layout = device.createBindGroupLayout({   entries: [     {       binding: 0,       visibility: GPUShaderStage.VERTEX,       buffer: {} // <- UBO 的简写     }   ] })

描述采样器对象:GPUSamplerBindingLayout

enum GPUSamplerBindingType {   "filtering",   "non-filtering",   "comparison", };  dictionary GPUSamplerBindingLayout {     GPUSamplerBindingType type = "filtering"; };

绑定组布局对象中,用于描述对应绑定组中的采样器资源时用的是 GPUSamplerBindingLayout 对象,它只有一个 type 字段,其类型是枚举类型 GPUSamplerBindingType,默认值是 "filtering"

它用来指示采样器的类型:过滤型、非过滤型和比较型。

系列博客目录传送门:https://xiaozhuanlan.com/topic/9587342601

  • 1 关系简易图解
  • 2 资源绑定组 GPUBindGroup
    • 如何创建
    • GPUBindGroupEntry 类型
      • GPUBindingResource
      • GPUBufferBinding
    • 译者注
    • 举例
      • ① 采样器资源
      • ② 纹理(视图)资源
      • ③ GPUBuffer 资源
    • 创建要遵守的规则
  • 3 资源绑定组的布局 GPUBindGroupLayout
    • 如何创建
      • GPUBindGroupLayoutEntry 类型
      • 描述缓存对象:GPUBufferBindingLayout
      • 描述采样器对象:GPUSamplerBindingLayout


资源绑定,即 JavaScript 中(即 CPU 端)如何对待传递到 GPU 的数据进行组织、分配的一种设计。

为了完成这个过程(CPU到GPU),WebGPU 设计了几个对象用于管理这些数据,这些数据包括 某些GPUBuffer(例如UBO,但是不包括VBO)、GPUTexture、GPUSampler、存储型纹理、外部纹理五种,这几个对象是:

  • 资源绑定组(以后均简称绑定组)- GPUBindGroup
  • 资源绑定组布局(以后称为绑定组的布局对象)- GPUBindGroupLayout
  • 管线布局 – GPUPipelineLayout

和规范中顺序略有不同,我按我上面这个来。

1 关系简易图解

     GPUBindGroup <--- 1 ---┓                动区                     GPUBindGroupLayout   ----------- GPUPipelineLayout <--- N ---┛                静区     |     1     ↓ GPUPipelineBase

简单的说就是绑定组有其布局,管线也有其布局;

绑定组的布局负责告诉资源长什么样子,管线的布局告诉管线着色器里头有多少类和分别有多少个资源坑位要进来;

两个布局负责沟通,那绑定组、管线就各司其职(一个负责组织管线所需的资源,一个负责某个渲染过程)。

2 资源绑定组 GPUBindGroup

资源绑定组,GPUBindGroup,一般会简单称之为“绑定组”,它组织了一些 资源,这些资源在某个具体的着色阶段一起起作用。

所谓的资源,就是 GPUBuffer、纹理、采样器等数据类型的对象。

如何创建

通过设备对象的 createBindGroup 方法创建,它需要一个必选的对象参数,这个对象参数要满足 GPUBindGroupDescriptor 类型。

dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {   required GPUBindGroupLayout layout;   required sequence<GPUBindGroupEntry> entries; };

看得出 GPUBindGroupDescriptor 类型需要两个必选参数:

  • 参数 layoutGPUBindGroupLayout 类型,通常称这个参数为资源绑定组的布局对象,有时候简单点就说对应的布局对象,下面会详细介绍这个类型;
  • 参数 entries,一个数组,每个元素皆为 GPUBindGroupEntry 类型,具体解释见下文。

GPUBindGroupEntry 类型

GPUBindGroupEntry 类型的对象,指代一种在着色阶段要用到的资源,包括一些简单的元数据。

这里的资源,在 WebGPU 中使用 GPUBindingResource 来定义。

dictionary GPUBindGroupEntry {   required GPUIndex32 binding;   required GPUBindingResource resource; };

GPUBindGroupEntry 对象的字段 binding 是一个 unsigned long 类型的数字,表示这个资源在着色器代码中的 location(在 WGSL 会介绍),即告诉着色器代码要从几号坑位取数据,一对一的。

而另一个字段 resource 自然指的就是这个下面要介绍的 GPUBindingResource 了。

GPUBindingResource

有四种 资源:采样器、纹理(视图)、缓存、外部纹理。

typedef (GPUSampler or GPUTextureView or GPUBufferBinding or GPUExternalTexture) GPUBindingResource;

常见的是前三种,第四种通常用于视频类型的纹理,有兴趣了解的读者可自行查阅纹理部分的章节。

第一种和第二种还比较好理解,在采样器和纹理章节能了解到如何创建,第三种并不是 GPUBuffer 的直接传递,而是嵌套了个对象,是 GPUBufferBinding 类型的,见下文:

GPUBufferBinding

dictionary GPUBufferBinding {   required GPUBuffer buffer;   GPUSize64 offset = 0;   GPUSize64 size; };

到这里就有熟悉的类型了,即 GPUBuffer

除此之外还有另外两个字段, offsetsize,前者默认值是 0,表示要从 GPUBuffer 的第几个字节开始,后者则为要从 GPUBuffer 的 offset 处向后取多少个字节。

译者注

通过 GPUBindGroup,明确地把一堆资源挨个(每个 entry)合并打包在一个组里,并且是按顺序(参数 binding)组织在一起。这就好比做菜时的食材,按顺序罗列在灶台边,做这道菜的是一组(绑定组),做另一道菜的是另一组(绑定组)。

举例

const bindGroup = device.createBindGroup({   layout: myBindGroupLayout, // 这个下面会介绍,这里假装已经有了   entries: [     /* ... */   ] })

① 采样器资源

entries: [   {     binding: 0,     resource: device.createSampler({ /* ... */ })   },   /* ... */ ]

② 纹理(视图)资源

entries: [   /* ... */,   {     binding: 1,     resource: myTexture.createView()   },   /* ... */ ]

③ GPUBuffer 资源

entries: [   /* ... */   {     binding: 2,     resource: {       buffer: uniformBuffer, // 通常通过绑定组传递的是 UBO,不绝对,       size: 16     }   } ]

创建要遵守的规则

  • descriptor.layout 字段必须是一个有效的布局对象
  • descriptor.layout 对象的 entries 数量必须与 descriptor.entries 的数量一致

对于每个 descriptor.entries 中的 GPUBindGroupEntry (此处以 bindEntry 指代)来说:

  • 此 bindEntry 的 binding 数字必须与 descriptor.layout 中的某一个一致,也即一一对应关系
  • 如果 descriptor.layout.entries 中的某个 GPUBindGroupLayoutEntry 对象:
    • 有 sampler 字段,那么 bindEntry.resource 就必须是一个有效的 GPUSampler,而且此 GPUBindGroupLayoutEntry 的 sampler 字段的 type 属性
    • "filtering",那么 bindEntry.resource 这个 GPUSampler 就不能是比较型采样器(即 isComparison 这个内部变量是 false);
    • "non-filering",那么 bindEntry.resource 这个 GPUSampler 既不能是比较型采样器,其 isFiltering 内部属性也不能是 true;
    • "comparison",那么 bindEntry.resource 这个 GPUSampler 就必须是比较型采样器(即 isComparison 内部属性是 true)
    • 有 texture 字段,那么 bindEntry.resource 必须是一个有效的 GPUTextureView,且此 GPUBindGroupLayoutEntry 的
    • texture 字段的 viewDimension 属性必须与 bindEntry.resource 这个 GPUTextureView 的 dimension 一致;
    • texture 字段的 sampleType 属性与 bindEntry.resource 这个 GPUTextureView 的 format 兼容;令 bindEntry.resource 这个 GPUTextureView 原本的纹理对象为 T,此时 T 的 usage 必须包括 "TEXTURE_BINDING"
    • texture 字段的 multisampled 属性是 true,那么上一条设定的纹理对象 T 的 sampleCount 必须大于1,否则 T.sampleCount 必须是 1.
    • 有 storageTexture 字段,那么 bindEntry.resource 必须是一个有效的 GPUTextureView 对象,此时令 T 为 bindEntry.resource 这个 GPUTextureView 对象原本的纹理对象:
    • 此 storageTexture 字段的 viewDimension 必须与 bindEntry.resource 这个 GPUTextureView 的 dimension 一致;
    • 此 storageTexture 字段的 format 必须与 bindEntry.resource 这个 GPUTextureView 的创建参数(GPUTextureViewDescriptor,创建完成后被内置,JavaScript 看不到)的 format 参数一致;
    • T 对象的 usage 必须包括 "STORAGE_BINDING"
    • 有 buffer 字段,那么 bindEntry.resource 必须是一个 GPUBufferBinding 对象,且 bindEntry.resource.buffer 必须是一个有效的 GPUBuffer 对象,不妨令这个 GPUBuffer 对象为 B 对象,且此 buffer 字段的 type 是:
    • "uniform",那么 B.usage 必须包括 "UNIFORM",且 bindEntry.resource.size 必须小于等于设备限制列表中的 maxUniformBufferBindingSize 值,bindEntry.resource.offset 必须是设备限制列表中 minUniformBufferOffsetAlignment 的倍数
    • "storage""read-only-storage",B.usage 必须包括 "STORAGE",且 bindEntry.resource.size 小于等于设备限制列表中的 maxStorageBufferBindingSize,bindEntry.resource.offset 必须是设备限制列表中的 minStorageBufferOffsetAlignment 的倍数

满足以上要求后,基本上绑定组对象就能创建成功,仍有一些可能不常用的细节需要读者自行查阅文档。

3 资源绑定组的布局 GPUBindGroupLayout

一个资源绑定组的布局对象,是 GPUBindGroupLayout 类型,简称绑定组的布局(对象),它的作用是联系与它配套的绑定组和对应阶段的着色器,告诉管线在什么着色阶段传入的数据长什么样子,是何种类。

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

如何创建

调用设备对象的 createBindGroupLayout 方法,即可创建一个绑定组布局对象。

此方法需要一个参数对象,需符合 GPUBindGroupLayoutDescriptor 类型:

dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {     required sequence<GPUBindGroupLayoutEntry> entries; };

它只有一个必选成员 entries,是一个数组,数组的每个元素是 GPUBindGroupLayoutEntry 类型的对象。

GPUBindGroupLayoutEntry 类型

GPUBindGroupLayoutEntry 描述一个在着色器中能被访问到的资源长什么样子,且如何找到它。

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,unsigned long 类型的数字,指定该 entry(也即资源)绑定号,绑定号在一个绑定组布局对象的 entries 数组所有元素中是唯一的,且必须和绑定组中的 entry 有对应,以便于在 WGSL 代码中访问对应资源;
  • 参数 visibilityGPUShaderStageFlags 类型,需从 GPUShaderStage 中访问枚举值,表示该 entry 在什么着色阶段可见,例如指定 visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,就意味着这个 entry 所描述的资源在顶点着色阶段和偏远着色阶段均可见。最后一个 COMPUTE 是计算管线的计算阶段。

还必须接受一个键值对作为此 entry 描述的资源的信息对象,需从 buffersamplertexturestorageTextureexternalTexture 中选一个。

描述缓存对象:GPUBufferBindingLayout

enum GPUBufferBindingType {   "uniform",   "storage",   "read-only-storage", };  dictionary GPUBufferBindingLayout {   GPUBufferBindingType type = "uniform";   boolean hasDynamicOffset = false;   GPUSize64 minBindingSize = 0; };

绑定组传递的 GPUBuffer 只有两种,UBO(即 "uniform" 类型的 GPUBuffer)和存储型 GPUBuffer,其中后者又分存储型("storage")和只读存储型("read-only-storage")两小种,通过 type 字段标识,默认值是 “uniform”,type 字段只能是 GPUBufferBindingType 枚举中的一个。

hasDynamicOffset 表示缓存对象是否有动态偏移值,默认是 false;

minBindingSize 表示的是被绑定的缓存对象的最小绑定大小,默认是 0(byte);

因为 type 的默认值是 “uniform”,所以如果你准备创建一个绑定组,并考虑到有 ubo 的传递,那么其实可以对某个 entry 简写成:

const layout = device.createBindGroupLayout({   entries: [     {       binding: 0,       visibility: GPUShaderStage.VERTEX,       buffer: {} // <- UBO 的简写     }   ] })

描述采样器对象:GPUSamplerBindingLayout

enum GPUSamplerBindingType {   "filtering",   "non-filtering",   "comparison", };  dictionary GPUSamplerBindingLayout {     GPUSamplerBindingType type = "filtering"; };

绑定组布局对象中,用于描述对应绑定组中的采样器资源时用的是 GPUSamplerBindingLayout 对象,它只有一个 type 字段,其类型是枚举类型 GPUSamplerBindingType,默认值是 "filtering"

它用来指示采样器的类型:过滤型、非过滤型和比较型。

系列博客目录传送门:https://xiaozhuanlan.com/topic/9587342601

  • 1 关系简易图解
  • 2 资源绑定组 GPUBindGroup
    • 如何创建
    • GPUBindGroupEntry 类型
      • GPUBindingResource
      • GPUBufferBinding
    • 译者注
    • 举例
      • ① 采样器资源
      • ② 纹理(视图)资源
      • ③ GPUBuffer 资源
    • 创建要遵守的规则
  • 3 资源绑定组的布局 GPUBindGroupLayout
    • 如何创建
      • GPUBindGroupLayoutEntry 类型
      • 描述缓存对象:GPUBufferBindingLayout
      • 描述采样器对象:GPUSamplerBindingLayout


资源绑定,即 JavaScript 中(即 CPU 端)如何对待传递到 GPU 的数据进行组织、分配的一种设计。

为了完成这个过程(CPU到GPU),WebGPU 设计了几个对象用于管理这些数据,这些数据包括 某些GPUBuffer(例如UBO,但是不包括VBO)、GPUTexture、GPUSampler、存储型纹理、外部纹理五种,这几个对象是:

  • 资源绑定组(以后均简称绑定组)- GPUBindGroup
  • 资源绑定组布局(以后称为绑定组的布局对象)- GPUBindGroupLayout
  • 管线布局 – GPUPipelineLayout

和规范中顺序略有不同,我按我上面这个来。

1 关系简易图解

     GPUBindGroup <--- 1 ---┓                动区                     GPUBindGroupLayout   ----------- GPUPipelineLayout <--- N ---┛                静区     |     1     ↓ GPUPipelineBase

简单的说就是绑定组有其布局,管线也有其布局;

绑定组的布局负责告诉资源长什么样子,管线的布局告诉管线着色器里头有多少类和分别有多少个资源坑位要进来;

两个布局负责沟通,那绑定组、管线就各司其职(一个负责组织管线所需的资源,一个负责某个渲染过程)。

2 资源绑定组 GPUBindGroup

资源绑定组,GPUBindGroup,一般会简单称之为“绑定组”,它组织了一些 资源,这些资源在某个具体的着色阶段一起起作用。

所谓的资源,就是 GPUBuffer、纹理、采样器等数据类型的对象。

如何创建

通过设备对象的 createBindGroup 方法创建,它需要一个必选的对象参数,这个对象参数要满足 GPUBindGroupDescriptor 类型。

dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {   required GPUBindGroupLayout layout;   required sequence<GPUBindGroupEntry> entries; };

看得出 GPUBindGroupDescriptor 类型需要两个必选参数:

  • 参数 layoutGPUBindGroupLayout 类型,通常称这个参数为资源绑定组的布局对象,有时候简单点就说对应的布局对象,下面会详细介绍这个类型;
  • 参数 entries,一个数组,每个元素皆为 GPUBindGroupEntry 类型,具体解释见下文。

GPUBindGroupEntry 类型

GPUBindGroupEntry 类型的对象,指代一种在着色阶段要用到的资源,包括一些简单的元数据。

这里的资源,在 WebGPU 中使用 GPUBindingResource 来定义。

dictionary GPUBindGroupEntry {   required GPUIndex32 binding;   required GPUBindingResource resource; };

GPUBindGroupEntry 对象的字段 binding 是一个 unsigned long 类型的数字,表示这个资源在着色器代码中的 location(在 WGSL 会介绍),即告诉着色器代码要从几号坑位取数据,一对一的。

而另一个字段 resource 自然指的就是这个下面要介绍的 GPUBindingResource 了。

GPUBindingResource

有四种 资源:采样器、纹理(视图)、缓存、外部纹理。

typedef (GPUSampler or GPUTextureView or GPUBufferBinding or GPUExternalTexture) GPUBindingResource;

常见的是前三种,第四种通常用于视频类型的纹理,有兴趣了解的读者可自行查阅纹理部分的章节。

第一种和第二种还比较好理解,在采样器和纹理章节能了解到如何创建,第三种并不是 GPUBuffer 的直接传递,而是嵌套了个对象,是 GPUBufferBinding 类型的,见下文:

GPUBufferBinding

dictionary GPUBufferBinding {   required GPUBuffer buffer;   GPUSize64 offset = 0;   GPUSize64 size; };

到这里就有熟悉的类型了,即 GPUBuffer

除此之外还有另外两个字段, offsetsize,前者默认值是 0,表示要从 GPUBuffer 的第几个字节开始,后者则为要从 GPUBuffer 的 offset 处向后取多少个字节。

译者注

通过 GPUBindGroup,明确地把一堆资源挨个(每个 entry)合并打包在一个组里,并且是按顺序(参数 binding)组织在一起。这就好比做菜时的食材,按顺序罗列在灶台边,做这道菜的是一组(绑定组),做另一道菜的是另一组(绑定组)。

举例

const bindGroup = device.createBindGroup({   layout: myBindGroupLayout, // 这个下面会介绍,这里假装已经有了   entries: [     /* ... */   ] })

① 采样器资源

entries: [   {     binding: 0,     resource: device.createSampler({ /* ... */ })   },   /* ... */ ]

② 纹理(视图)资源

entries: [   /* ... */,   {     binding: 1,     resource: myTexture.createView()   },   /* ... */ ]

③ GPUBuffer 资源

entries: [   /* ... */   {     binding: 2,     resource: {       buffer: uniformBuffer, // 通常通过绑定组传递的是 UBO,不绝对,       size: 16     }   } ]

创建要遵守的规则

  • descriptor.layout 字段必须是一个有效的布局对象
  • descriptor.layout 对象的 entries 数量必须与 descriptor.entries 的数量一致

对于每个 descriptor.entries 中的 GPUBindGroupEntry (此处以 bindEntry 指代)来说:

  • 此 bindEntry 的 binding 数字必须与 descriptor.layout 中的某一个一致,也即一一对应关系
  • 如果 descriptor.layout.entries 中的某个 GPUBindGroupLayoutEntry 对象:
    • 有 sampler 字段,那么 bindEntry.resource 就必须是一个有效的 GPUSampler,而且此 GPUBindGroupLayoutEntry 的 sampler 字段的 type 属性
    • "filtering",那么 bindEntry.resource 这个 GPUSampler 就不能是比较型采样器(即 isComparison 这个内部变量是 false);
    • "non-filering",那么 bindEntry.resource 这个 GPUSampler 既不能是比较型采样器,其 isFiltering 内部属性也不能是 true;
    • "comparison",那么 bindEntry.resource 这个 GPUSampler 就必须是比较型采样器(即 isComparison 内部属性是 true)
    • 有 texture 字段,那么 bindEntry.resource 必须是一个有效的 GPUTextureView,且此 GPUBindGroupLayoutEntry 的
    • texture 字段的 viewDimension 属性必须与 bindEntry.resource 这个 GPUTextureView 的 dimension 一致;
    • texture 字段的 sampleType 属性与 bindEntry.resource 这个 GPUTextureView 的 format 兼容;令 bindEntry.resource 这个 GPUTextureView 原本的纹理对象为 T,此时 T 的 usage 必须包括 "TEXTURE_BINDING"
    • texture 字段的 multisampled 属性是 true,那么上一条设定的纹理对象 T 的 sampleCount 必须大于1,否则 T.sampleCount 必须是 1.
    • 有 storageTexture 字段,那么 bindEntry.resource 必须是一个有效的 GPUTextureView 对象,此时令 T 为 bindEntry.resource 这个 GPUTextureView 对象原本的纹理对象:
    • 此 storageTexture 字段的 viewDimension 必须与 bindEntry.resource 这个 GPUTextureView 的 dimension 一致;
    • 此 storageTexture 字段的 format 必须与 bindEntry.resource 这个 GPUTextureView 的创建参数(GPUTextureViewDescriptor,创建完成后被内置,JavaScript 看不到)的 format 参数一致;
    • T 对象的 usage 必须包括 "STORAGE_BINDING"
    • 有 buffer 字段,那么 bindEntry.resource 必须是一个 GPUBufferBinding 对象,且 bindEntry.resource.buffer 必须是一个有效的 GPUBuffer 对象,不妨令这个 GPUBuffer 对象为 B 对象,且此 buffer 字段的 type 是:
    • "uniform",那么 B.usage 必须包括 "UNIFORM",且 bindEntry.resource.size 必须小于等于设备限制列表中的 maxUniformBufferBindingSize 值,bindEntry.resource.offset 必须是设备限制列表中 minUniformBufferOffsetAlignment 的倍数
    • "storage""read-only-storage",B.usage 必须包括 "STORAGE",且 bindEntry.resource.size 小于等于设备限制列表中的 maxStorageBufferBindingSize,bindEntry.resource.offset 必须是设备限制列表中的 minStorageBufferOffsetAlignment 的倍数

满足以上要求后,基本上绑定组对象就能创建成功,仍有一些可能不常用的细节需要读者自行查阅文档。

3 资源绑定组的布局 GPUBindGroupLayout

一个资源绑定组的布局对象,是 GPUBindGroupLayout 类型,简称绑定组的布局(对象),它的作用是联系与它配套的绑定组和对应阶段的着色器,告诉管线在什么着色阶段传入的数据长什么样子,是何种类。

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

如何创建

调用设备对象的 createBindGroupLayout 方法,即可创建一个绑定组布局对象。

此方法需要一个参数对象,需符合 GPUBindGroupLayoutDescriptor 类型:

dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {     required sequence<GPUBindGroupLayoutEntry> entries; };

它只有一个必选成员 entries,是一个数组,数组的每个元素是 GPUBindGroupLayoutEntry 类型的对象。

GPUBindGroupLayoutEntry 类型

GPUBindGroupLayoutEntry 描述一个在着色器中能被访问到的资源长什么样子,且如何找到它。

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,unsigned long 类型的数字,指定该 entry(也即资源)绑定号,绑定号在一个绑定组布局对象的 entries 数组所有元素中是唯一的,且必须和绑定组中的 entry 有对应,以便于在 WGSL 代码中访问对应资源;
  • 参数 visibilityGPUShaderStageFlags 类型,需从 GPUShaderStage 中访问枚举值,表示该 entry 在什么着色阶段可见,例如指定 visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,就意味着这个 entry 所描述的资源在顶点着色阶段和偏远着色阶段均可见。最后一个 COMPUTE 是计算管线的计算阶段。

还必须接受一个键值对作为此 entry 描述的资源的信息对象,需从 buffersamplertexturestorageTextureexternalTexture 中选一个。

描述缓存对象:GPUBufferBindingLayout

enum GPUBufferBindingType {   "uniform",   "storage",   "read-only-storage", };  dictionary GPUBufferBindingLayout {   GPUBufferBindingType type = "uniform";   boolean hasDynamicOffset = false;   GPUSize64 minBindingSize = 0; };

绑定组传递的 GPUBuffer 只有两种,UBO(即 "uniform" 类型的 GPUBuffer)和存储型 GPUBuffer,其中后者又分存储型("storage")和只读存储型("read-only-storage")两小种,通过 type 字段标识,默认值是 “uniform”,type 字段只能是 GPUBufferBindingType 枚举中的一个。

hasDynamicOffset 表示缓存对象是否有动态偏移值,默认是 false;

minBindingSize 表示的是被绑定的缓存对象的最小绑定大小,默认是 0(byte);

因为 type 的默认值是 “uniform”,所以如果你准备创建一个绑定组,并考虑到有 ubo 的传递,那么其实可以对某个 entry 简写成:

const layout = device.createBindGroupLayout({   entries: [     {       binding: 0,       visibility: GPUShaderStage.VERTEX,       buffer: {} // <- UBO 的简写     }   ] })

描述采样器对象:GPUSamplerBindingLayout

enum GPUSamplerBindingType {   "filtering",   "non-filtering",   "comparison", };  dictionary GPUSamplerBindingLayout {     GPUSamplerBindingType type = "filtering"; };

绑定组布局对象中,用于描述对应绑定组中的采样器资源时用的是 GPUSamplerBindingLayout 对象,它只有一个 type 字段,其类型是枚举类型 GPUSamplerBindingType,默认值是 "filtering"

它用来指示采样器的类型:过滤型、非过滤型和比较型。

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » WebGPU 规范篇 06 资源及其打组绑定求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们