bindGroupFor method

GPUBindGroup bindGroupFor(
  1. WebGpuBindingLayouts layouts,
  2. int group,
  3. Map<int, WebGpuSlice>? blocks,
  4. Map<int, GPUTextureView>? views,
  5. Map<int, GPUSampler>? samplers,
)

The bind group for one @group of layouts, assembled from what the pass has bound and cached by what went into it.

A binding the pass never filled gets a neutral resource rather than being left out: WebGPU refuses an incomplete group outright, and the contract already says a declared sampler must have something bound to it. An unfilled block reads the zeroed buffer, which is what GL would have given it.

Implementation

GPUBindGroup bindGroupFor(
  WebGpuBindingLayouts layouts,
  int group,
  Map<int, WebGpuSlice>? blocks,
  Map<int, GPUTextureView>? views,
  Map<int, GPUSampler>? samplers,
) {
  final shape = layouts.shapes[group];
  final resources = <Object>[];
  final entries = <GPUBindGroupEntry>[];
  for (final bound in shape.blocks) {
    final block = bound.block;
    final buffer = blocks?[block.binding]?.buffer ?? _zeroBlock;
    resources.add(buffer);
    entries.add(
      GPUBindGroupEntry.buffer(
        binding: block.binding,
        // Offset zero and the block's own size: the offset a draw actually
        // wants rides on `setBindGroup` instead, which is what
        // `hasDynamicOffset` bought.
        resource: GPUBufferBinding(
          buffer: buffer,
          offset: 0,
          size: block.sizeInBytes,
        ),
      ),
    );
  }
  for (final bound in shape.samplers) {
    final sampler = bound.sampler;
    final view =
        views?[sampler.textureBinding] ?? _blankView(sampler.dimension);
    final object =
        samplers?[sampler.samplerBinding] ??
        samplerFor(SamplerOptions.linearRepeat);
    resources
      ..add(view)
      ..add(object);
    entries
      ..add(
        GPUBindGroupEntry.textureView(
          binding: sampler.textureBinding,
          resource: view,
        ),
      )
      ..add(
        GPUBindGroupEntry.sampler(
          binding: sampler.samplerBinding,
          resource: object,
        ),
      );
  }
  return _bindGroups[_BindGroupKey(
    layouts.groups[group],
    resources,
  )] ??= guard(
    'a bind group for group $group',
    () => gpuDevice.createBindGroup(
      GPUBindGroupDescriptor(
        layout: layouts.groups[group],
        entries: entries.toJS,
        label: 'group $group',
      ),
    ),
  );
}