Align the WebGL backend's flat-varying provoking vertex with WebGPU's.
A flat varying is sourced from ONE corner of the triangle, and the two
backends do not default to the same one:
Backend
Convention
OpenGL ES 3.0 (glslVersion: GLSL3)
last vertex of the primitive, fixed by spec
WGSL @interpolate(flat) as three emits it
first-vertex sampling
That only becomes observable when a flat varying differs BETWEEN a triangle's
corners — which, in the shipped materials, is exactly one case: the mesh pick
shader's vElementId, whose source is gl_VertexID / vertexIndex
(spec §6.5). Left alone, the same click on the same triangle (i0, i1, i2)
reports i2 on WebGL and i0 on WebGPU.
WEBGL_provoking_vertex lets the WebGL side adopt WebGPU's first-vertex rule, so
the two agree wherever the extension exists. Where it does not, the divergence
stands as a documented §6.4 exception and the pick contract is unchanged: at
vertex granularity the answer is "a corner vertex of the front-most triangle
under the cursor" — the cursor is over the face, not a vertex, so every corner is
equally valid and no consumer may assume a specific one.
Why context-wide state is acceptable here
provokingVertexWEBGL is not scoped to a program or a draw call; it changes the
convention for the whole context. That is safe because every OTHER flat varying
in the shipped materials is a per-instance constant — point and gsplat quads
and line segments all carry the same id, sharpness and cap flags at every corner
of their expanded quad, so which corner supplies the value is unobservable. Mesh
is the only geometry whose flat inputs vary within a primitive, hence the only
one that can see the flip at all.
Align the WebGL backend's
flat-varying provoking vertex with WebGPU's.A
flatvarying is sourced from ONE corner of the triangle, and the two backends do not default to the same one:glslVersion: GLSL3)@interpolate(flat)as three emits itThat only becomes observable when a
flatvarying differs BETWEEN a triangle's corners — which, in the shipped materials, is exactly one case: the mesh pick shader'svElementId, whose source isgl_VertexID/vertexIndex(spec §6.5). Left alone, the same click on the same triangle(i0, i1, i2)reportsi2on WebGL andi0on WebGPU.WEBGL_provoking_vertexlets the WebGL side adopt WebGPU's first-vertex rule, so the two agree wherever the extension exists. Where it does not, the divergence stands as a documented §6.4 exception and the pick contract is unchanged: at vertex granularity the answer is "a corner vertex of the front-most triangle under the cursor" — the cursor is over the face, not a vertex, so every corner is equally valid and no consumer may assume a specific one.Why context-wide state is acceptable here
provokingVertexWEBGLis not scoped to a program or a draw call; it changes the convention for the whole context. That is safe because every OTHERflatvarying in the shipped materials is a per-instance constant — point and gsplat quads and line segments all carry the same id, sharpness and cap flags at every corner of their expanded quad, so which corner supplies the value is unobservable. Mesh is the only geometry whoseflatinputs vary within a primitive, hence the only one that can see the flip at all.