Conservative rasterization on an M1: draw a bigger polygon
D3D12 conservative rasterization, which Metal lacks on an M1 Mac, is now emulated by replacing each triangle with a slightly larger polygon before Metal rasterizes it.
What changed
Normally a GPU lights a pixel only if the triangle covers the pixel's centre. With conservative rasterization it lights every pixel the triangle touches at all. Voxelizers and some shadow and occlusion techniques depend on this, because thin or tiny triangles must not fall between pixel centres. Metal has no such mode on this M1 Max, so the layer reported it as not supported. It now reports Tier 1, which allows the result to be off by up to half a pixel.
A pipeline with conservative rasterization now takes the path the layer already uses for geometry shaders. The vertex shader writes its outputs to a buffer. A generated compute-like "object function" then replaces each triangle with a polygon of up to 7 vertices: the triangle's pixel-aligned bounding box, clipped against the triangle's three edges, each moved outwards by just over half a pixel. Every pixel whose square touches the triangle has its centre inside that polygon, so Metal's ordinary rasterizer lights it. The new vertices get their attributes (colours, texture coordinates) by extrapolating the original triangle, with perspective correction, as D3D12 allows. With multisampling (several coverage samples per pixel) the edges move out a full pixel so that every sample is covered, and a new SPIRV-Cross patch (0035) discards the extra pixels in the fragment function.
The interesting part
The first version got the coverage right but the attributes 0.4% wrong on a long sliver. The cause was Metal's vertex snapping: the rasterizer rounds vertex positions to 1/256 of a pixel. For a normal triangle that doesn't matter, but these new vertices sit on the plane of an extrapolated attribute, and rounding them moves them off it. Rounding the polygon's vertices to the same 1/256 grid before computing their weights fixed it.
The review found two combinations that are now switched off with a warning rather than drawn wrong: strip cut indices (the capture would treat them as vertices) and wireframe (invalid with conservative rasterization in D3D12).
The gallery scene shows three thin slivers on a 32x18 target, enlarged 20 times. Drawn normally (left), they break into dashes or vanish entirely. Drawn conservatively (right), every touched pixel lights up.
Numbers
- Full run: 797 pass, 26 fail, 92 skip of 915; 0 newly failing, 1 newly passing, the new api/conservative_raster (2,160 checks over 8 cases).
- Previous run: 796 pass, 26 fail, 92 skip of 914.
- vkd3d-proton's test_conservative_rasterization_dxbc and _dxil now run 28 checks each instead of 10, all passing; they still skip their Tier 3 part.
- pass
- fail
- skip
suite · share of each row's total
- vkd3d-proton472 pass, 17 fail, 88 skip of 577
- vkd3d177 pass, 9 fail, 4 skip of 190
- apps77 pass, 0 fail, 0 skip of 77
- api (+1)67 pass, 0 fail, 0 skip of 67
- samples4 pass, 0 fail, 0 skip of 4