in src/webgpu/shader/execution/expression/call/builtin/texture_utils.ts [4731:4809]
function buildBinnedCalls<T extends Dimensionality>(calls: TextureCall<T>[]) {
const args: string[] = [];
const fields: string[] = [];
const data: number[] = [];
const prototype = calls[0];
if (isBuiltinGather(prototype.builtin) && prototype['componentType']) {
args.push(`/* component */ ${wgslExpr(prototype['component']!)}`);
}
// All texture builtins take a Texture
args.push('T');
if (builtinNeedsSampler(prototype.builtin)) {
// textureSample*() builtins take a sampler as the second argument
args.push('S');
}
for (const name of kTextureCallArgNames) {
const value = prototype[name];
if (value !== undefined) {
if (name === 'offset') {
args.push(`/* offset */ ${wgslExpr(value)}`);
} else if (name === 'component') {
// was handled above
} else {
const type =
name === 'mipLevel'
? prototype.levelType!
: name === 'arrayIndex'
? prototype.arrayIndexType!
: name === 'sampleIndex'
? prototype.sampleIndexType!
: name === 'bias' || name === 'depthRef' || name === 'ddx' || name === 'ddy'
? 'f'
: prototype.coordType;
if (name !== 'derivativeMult') {
args.push(
`args.${name}${
name === 'coords' && builtinNeedsDerivatives(prototype.builtin)
? ' + derivativeBase * args.derivativeMult'
: ''
}`
);
}
fields.push(`@align(16) ${name} : ${wgslTypeFor(value, type)}`);
}
}
}
for (const call of calls) {
for (const name of kTextureCallArgNames) {
const value = call[name];
assert(
(prototype[name] === undefined) === (value === undefined),
'texture calls are not binned correctly'
);
if (value !== undefined && name !== 'offset' && name !== 'component') {
const type = getCallArgType<T>(call, name);
const bitcastToU32 = kBitCastFunctions[type];
if (value instanceof Array) {
for (const c of value) {
data.push(bitcastToU32(c));
}
} else {
data.push(bitcastToU32(value));
}
// All fields are aligned to 16 bytes.
while ((data.length & 3) !== 0) {
data.push(0);
}
}
}
}
const expr = `${prototype.builtin}(${args.join(', ')})`;
return { expr, fields, data };
}