in src/webgpu/shader/execution/expression/expression.ts [664:779]
function basicExpressionShaderBody(
expressionBuilder: ExpressionBuilder,
params: ShaderBuilderParams
): string {
const { parameterTypes, resultType, cases, inputSource } = params;
assert(
scalarTypeOf(resultType).kind !== 'abstract-int',
`abstractIntShaderBuilder should be used when result type is 'abstract-int'`
);
assert(
scalarTypeOf(resultType).kind !== 'abstract-float',
`abstractFloatShaderBuilder should be used when result type is 'abstract-float'`
);
let nextUniqueIDSuffix = 0;
const convHelpers: TypeConversionHelpers = {
wgsl: '',
uniqueID: () => `cts_symbol_${nextUniqueIDSuffix++}`,
};
if (inputSource === 'const') {
let constEvaluationMode = params.constEvaluationMode;
if (constEvaluationMode === undefined) {
if (parameterTypes.some(ty => isAbstractType(scalarTypeOf(ty)))) {
// Directly assign the expression to the output, to avoid an
// intermediate store, which will concretize the value early
constEvaluationMode = 'direct';
} else {
constEvaluationMode = globalTestConfig.unrollConstEvalLoops ? 'unrolled' : 'loop';
}
}
//////////////////////////////////////////////////////////////////////////
// Constant eval
//////////////////////////////////////////////////////////////////////////
let body = '';
let valuesArray = '';
switch (constEvaluationMode) {
case 'direct': {
body = cases
.map(
(c, i) =>
` outputs[${i}].value = ${toStorage(
resultType,
expressionBuilder(map(c.input, v => v.wgsl())),
convHelpers
)};`
)
.join('\n ');
break;
}
case 'unrolled': {
body = cases
.map((_, i) => {
const value = `values[${i}]`;
return ` outputs[${i}].value = ${toStorage(resultType, value, convHelpers)};`;
})
.join('\n ');
valuesArray = wgslValuesArray(cases, expressionBuilder);
break;
}
case 'loop': {
body = `
for (var i = 0u; i < ${cases.length}; i++) {
outputs[i].value = ${toStorage(resultType, `values[i]`, convHelpers)};
}`;
valuesArray = wgslValuesArray(cases, expressionBuilder);
break;
}
}
return `
${wgslOutputs(resultType, cases.length)}
${valuesArray}
${convHelpers.wgsl}
@compute @workgroup_size(1)
fn main() {
${body}
}
`;
} else {
//////////////////////////////////////////////////////////////////////////
// Runtime eval
//////////////////////////////////////////////////////////////////////////
// returns the WGSL expression to load the ith parameter of the given type from the input buffer
const paramExpr = (ty: Type, i: number) => fromStorage(ty, `inputs[i].param${i}`, convHelpers);
// resolves to the expression that calls the builtin
const expr = toStorage(
resultType,
expressionBuilder(parameterTypes.map(paramExpr)),
convHelpers
);
return `
struct Input {
${wgslMembers(parameterTypes.map(storageType), inputSource, i => `param${i}`)}
}
${wgslOutputs(resultType, cases.length)}
${wgslInputVar(inputSource, cases.length)}
${convHelpers.wgsl}
@compute @workgroup_size(1)
fn main() {
for (var i = 0; i < ${cases.length}; i++) {
outputs[i].value = ${expr};
}
}
`;
}
}