in src/webgpu/shader/execution/expression/expression.ts [1170:1268]
async function buildPipeline(
t: GPUTest,
shaderBuilder: ShaderBuilder,
shaderBuilderParams: ShaderBuilderParams,
outputBuffer: GPUBuffer,
pipelineCache: PipelineCache
): Promise<[GPUComputePipeline, GPUBindGroup]> {
const { parameterTypes, cases, inputSource } = shaderBuilderParams;
cases.forEach(c => {
const inputTypes = c.input instanceof Array ? c.input.map(i => i.type) : [c.input.type];
if (!objectEquals(inputTypes, parameterTypes)) {
const input_str = `[${inputTypes.join(',')}]`;
const param_str = `[${parameterTypes.join(',')}]`;
throw new Error(
`case input types ${input_str} do not match provided runner parameter types ${param_str}`
);
}
});
const source = shaderBuilder(shaderBuilderParams);
switch (inputSource) {
case 'const': {
// build the shader module
const module = t.device.createShaderModule({ code: source });
// build the pipeline
const pipeline = await t.device.createComputePipelineAsync({
layout: 'auto',
compute: { module, entryPoint: 'main' },
});
// build the bind group
const group = t.device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: { buffer: outputBuffer } }],
});
return [pipeline, group];
}
case 'uniform':
case 'storage_r':
case 'storage_rw': {
// Input values come from a uniform or storage buffer
// size in bytes of the input buffer
const caseStride = structStride(parameterTypes, inputSource);
const inputSize = align(cases.length * caseStride, 4);
// Holds all the parameter values for all cases
const inputData = new Uint8Array(inputSize);
// Pack all the input parameter values into the inputData buffer
for (let caseIdx = 0; caseIdx < cases.length; caseIdx++) {
const offset = caseIdx * caseStride;
structLayout(parameterTypes, inputSource, m => {
const arg = cases[caseIdx].input;
if (arg instanceof Array) {
arg[m.index].copyTo(inputData, offset + m.offset);
} else {
arg.copyTo(inputData, offset + m.offset);
}
});
}
// build the compute pipeline, if the shader hasn't been compiled already.
const pipeline = getOrCreate(pipelineCache, source, () => {
// build the shader module
const module = t.device.createShaderModule({ code: source });
// build the pipeline
return t.device.createComputePipeline({
layout: 'auto',
compute: { module, entryPoint: 'main' },
});
});
// build the input buffer
const inputBuffer = t.makeBufferWithContents(
inputData,
GPUBufferUsage.COPY_SRC |
(inputSource === 'uniform' ? GPUBufferUsage.UNIFORM : GPUBufferUsage.STORAGE)
);
// build the bind group
const group = t.device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: { buffer: outputBuffer } },
{ binding: 1, resource: { buffer: inputBuffer } },
],
});
return [pipeline, group];
}
}
}