Topology

Primitive Topology and Winding Order

primitive.topology decides how vertices group: point-list, line-list, line-strip, triangle-list (the default) or triangle-strip. The same six zig-zag vertices, one pipeline per topology:

Six vertices under the five primitive topologiesHTMLLive
<canvas id="gpu" width="600" height="100"></canvas>
<div id="names" style="display: flex; width: 600px; font: 13px Arial"></div>
<script type="module">
const code = /* wgsl */ `
struct Out { @builtin(position) pos: vec4f, @location(0) @interpolate(flat) panel: u32 }
@vertex fn vs(@builtin(vertex_index) v: u32, @builtin(instance_index) panel: u32) -> Out {
  let zigzag = vec2f(f32(v / 2) * 0.13, f32(v % 2) * 0.7);      // 6 vertices: 3 low, 3 high
  return Out(vec4f(-0.93 + f32(panel) * 0.4 + zigzag.x, -0.8 + zigzag.y + f32(v / 2) * 0.1,
                   0, 1), panel);
}
const colors = array(vec3f(.08, .40, .75), vec3f(.18, .49, .20), vec3f(.94, .42, 0),
                     vec3f(.42, .11, .60), vec3f(.78, .16, .16));
@fragment fn fs(in: Out) -> @location(0) vec4f { return vec4f(colors[in.panel], 1); }`;
const device = await (await navigator.gpu.requestAdapter()).requestDevice();
const context = gpu.getContext('webgpu'), format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
const module = device.createShaderModule({ code });
const topologies = ['point-list', 'line-list', 'line-strip', 'triangle-list',
  'triangle-strip'];
names.innerHTML = topologies.map((t) =>
  `<span style="flex: 1; text-align: center">${t}</span>`).join('');
const pipelines = await Promise.all(topologies.map((topology) =>
  device.createRenderPipelineAsync({ layout: 'auto', primitive: { topology },
    vertex: { module }, fragment: { module, targets: [{ format }] } })));
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({ colorAttachments: [{ loadOp: 'clear', storeOp: 'store',
  view: context.getCurrentTexture().createView(), clearValue: [0.96, 0.94, 0.90, 1] }] });
pipelines.forEach((pipeline, i) => {
  pass.setPipeline(pipeline);
  pass.draw(6, 1, 0, i);                         // the same 6 vertices, panel i
});
pass.end();
device.queue.submit([encoder.finish()]);
await device.queue.onSubmittedWorkDone();
window.__done = true;
</script>
Browser output of Listing 4.60
Browser output of 60

Points and lines are always one pixel wide (there is no lineWidth or point size), so thick lines and sprites are quads (Particles and Culling). Strips reuse vertices (four triangles from six vertices here, against two for the list), and alternate triangles are flipped so the strip keeps one winding order. With indexed strips set stripIndexFormat to use primitive restart (index 0xFFFF or 0xFFFFFFFF starts a new strip).