bindUniformBlock method
Fills the block called blockName and binds it. False where shader
declares no such block.
The two halves of the contract's rule, kept apart: a block the translator
dropped because nothing read it is an ordinary false, and a block that
exists without a member the caller named throws — the two ends disagree
about its shape, and zeros are a plausible value for most of what goes
through here.
The bytes go into the frame's uniform arena and the offset is remembered
for the draw. Nothing is bound to the pass yet: a GPUBindGroup is every
binding of one group at once, and the rest of this group may still be
coming.
Implementation
@override
bool bindUniformBlock(
ShaderHandle shader,
String blockName,
Map<String, Float32List> members,
) {
final stage = shader.backend as WebGpuShader;
final block = stage.blockNamed(blockName);
if (block == null) return false;
final data = Float32List(block.sizeInBytes ~/ 4);
for (final entry in members.entries) {
final member = _memberOf(block, entry.key);
final at = member.offsetInBytes ~/ 4;
if (at + entry.value.length > data.length) {
throw StateError(
'uniform block "$blockName" member "${entry.key}" wants '
'${entry.value.length} floats at offset $at, past the block\'s '
'${data.length}. std140 pads array elements to sixteen bytes; a '
'tightly packed array of scalars overruns exactly like this',
);
}
data.setRange(at, at + entry.value.length, entry.value);
}
_blocks.putIfAbsent(
block.group,
() => <int, WebGpuSlice>{},
)[block.binding] = _device.uniformArena.write(
ByteData.sublistView(data),
);
return true;
}