export async function runFragmentTest()

in src/webgpu/shader/execution/expression/call/builtin/subgroup_util.ts [480:587]


export async function runFragmentTest(
  t: SubgroupTest,
  format: GPUTextureFormat,
  fsShader: string,
  width: number,
  height: number,
  inputData: Uint32Array | Float32Array | Float16Array,
  checker: (data: Uint32Array) => Error | undefined
) {
  const vsShader = `
@vertex
fn vsMain(@builtin(vertex_index) index : u32) -> @builtin(position) vec4f {
  const vertices = array(
    vec2(-2, 4), vec2(-2, -4), vec2(2, 0),
  );
  return vec4f(vec2f(vertices[index]), 0, 1);
}`;

  assert(width >= 3, 'Minimum width is 3');
  assert(height >= 3, 'Minimum height is 3');
  const pipeline = t.device.createRenderPipeline({
    layout: 'auto',
    vertex: {
      module: t.device.createShaderModule({ code: vsShader }),
    },
    fragment: {
      module: t.device.createShaderModule({ code: fsShader }),
      targets: [{ format }],
    },
    primitive: {
      topology: 'triangle-list',
    },
  });

  const { blockWidth, blockHeight, bytesPerBlock } = getBlockInfoForTextureFormat(format);
  assert(bytesPerBlock !== undefined);

  const blocksPerRow = width / blockWidth;
  const blocksPerColumn = height / blockHeight;
  // 256 minimum arises from image copy requirements.
  const bytesPerRow = align(blocksPerRow * (bytesPerBlock ?? 1), 256);
  const byteLength = bytesPerRow * blocksPerColumn;
  const uintLength = byteLength / 4;

  const expandedInputData = new (
    inputData instanceof Uint32Array
      ? Uint32Array
      : inputData instanceof Float32Array
      ? Float32Array
      : Float16Array
  )(inputData.length * 4);
  for (let i = 0; i < inputData.length; ++i) {
    expandedInputData[i * 4] = inputData[i];
  }
  const buffer = t.makeBufferWithContents(
    expandedInputData,
    GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
  );

  const bg = t.device.createBindGroup({
    layout: pipeline.getBindGroupLayout(0),
    entries: [
      {
        binding: 0,
        resource: {
          buffer,
        },
      },
    ],
  });

  const framebuffer = t.createTextureTracked({
    size: [width, height],
    usage:
      GPUTextureUsage.COPY_SRC |
      GPUTextureUsage.COPY_DST |
      GPUTextureUsage.RENDER_ATTACHMENT |
      GPUTextureUsage.TEXTURE_BINDING,
    format,
  });

  const encoder = t.device.createCommandEncoder({ label: 'runFragmentTest' });
  const pass = encoder.beginRenderPass({
    colorAttachments: [
      {
        view: framebuffer.createView(),
        loadOp: 'clear',
        storeOp: 'store',
      },
    ],
  });
  pass.setPipeline(pipeline);
  pass.setBindGroup(0, bg);
  pass.draw(3);
  pass.end();
  t.queue.submit([encoder.finish()]);

  const copyBuffer = t.copyWholeTextureToNewBufferSimple(framebuffer, 0);
  const readback = await t.readGPUBufferRangeTyped(copyBuffer, {
    srcByteOffset: 0,
    type: Uint32Array,
    typedLength: uintLength,
    method: 'copy',
  });
  const data: Uint32Array = readback.data;

  t.expectOK(checker(data));
}