function buildBinnedCalls()

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 };
}