Computer Graphics · Rasterization
Conservative Rasterization and the Guarantee of Non-Empty Coverage
Standard rasterization may miss a pixel that a triangle touches, which breaks shadow volumes and voxelization; conservative rasterization over-covers by a bounded margin to make touching sufficient.
The rule that a fragment is generated when the pixel’s centre is inside the triangle has an asymmetry that is usually invisible: a pixel whose interior the triangle crosses but whose centre it misses produces nothing. For an image, the missing fragment is a fraction of a pixel of error, hidden by antialiasing. For any algorithm that treats the fragment as a certificate of intersection, the missing fragment is a wrong answer. Shadow volume extrusion, voxelization, occlusion queries, and collision-free visibility tests all need the opposite guarantee: if the triangle touches a pixel’s area, a fragment for that pixel must exist.
The shape of the guarantee
Conservative rasterization weakens the inside test from “the sample is inside the triangle” to “the pixel’s square overlaps the triangle”, with a tolerance. A pixel overlaps the triangle when its square intersects the triangle’s interior, which is a different geometric predicate: instead of evaluating the edge functions at one point, the test must decide whether three half-planes together contain any part of a square. That is a polygon-intersection question, and doing it exactly per pixel is more work than three sign tests.
The published formulations define the guarantee with an inflation. Each edge is pushed outward by a distance related to the pixel size, so the test becomes “is the pixel centre within the inflated triangle”, which restores the cheap point test at the cost of covering pixels the triangle does not touch. The inflation is bounded: a pixel is included if the triangle comes within a distance of it, and the margin is on the order of half a pixel diagonal in the conservative formulations that use a square. The result over-covers by at most a one-pixel fringe, and it never under-covers.
There are two strengths of the guarantee in the API. One covers a pixel if the triangle overlaps any part of it. The other covers a pixel only if the triangle fully covers it, used for cases where a partial certificate is not enough. Direct3D 12 exposes both, and Vulkan exposes an equivalent pair through a rasterization mode that requires the corresponding device feature. The full-coverage variant is the one used in occlusion culling, where the point is to prove that a region is hidden rather than merely touched.
/* Conservative point test: a pixel centre is covered if it lies inside the
triangle inflated by one pixel in every direction. Equivalent to testing
the centre against edge equations shifted by the edge's outward normal. */
static int conservative_test(const edge_t e[3], int px, int py, int64_t len[3])
{
/* len[i] approximates |normal| * subpixel-scale so that the shift is one
pixel of world distance, independent of how the edge is oriented. */
for (int i = 0; i < 3; i++) {
int64_t v = eval(&e[i], px * 256 + 128, py * 256 + 128);
if (v < -len[i]) return 0; /* centre is more than a pixel outside */
}
return 1;
}
The per-edge shift is a constant computed at setup from the edge’s length, so the per-pixel work stays at three comparisons. That is the entire performance argument for the inflated-triangle formulation: it converts a polygon-overlap query into the same three evaluations as the standard test, with different constants.
Why the extra pixels are the point
Algorithms that use coverage as a certificate accumulate a global result from many fragments. Voxelization writes a voxel occupied bit for every fragment; if a triangle clips the corner of a voxel and no fragment is generated, the voxel stays marked empty, and a later pass that treats empty voxels as free space will route through a solid. Shadow volume counting increments and decrements a stencil value per fragment; a missed fragment at a silhouette leaves the parity wrong along a whole ray, producing a lit pixel inside shadow or a shadowed pixel in light.
The common structure is that each fragment contributes an irreversible increment to some conservative quantity, and a missing fragment cannot be repaired later because nothing records that it should have existed. This is categorically different from image rendering, where a missing fragment at a silhouette produces a slightly wrong pixel whose error is bounded and local. The distinction explains why conservative rasterization is an option rather than the default: it costs real coverage accuracy, and only algorithms that need the certificate benefit.
The cost is not only wasted shading. Over-covered pixels receive fragments with attributes interpolated at positions outside the triangle, so the interpolated value can be an extrapolation. For a shader that writes occupancy this is irrelevant. For a shader that writes a colour or a normal, the extrapolated value can be far outside the range of the triangle’s vertex data, and a conservative pass that also shades must clamp or accept the artifact. This is the practical reason conservative mode is generally paired with a shader that does not care about its own attribute values.
Watertightness and neighbour agreement
A mesh rendered conservatively has a property that a mesh rendered normally does not: every pixel touched by the mesh receives at least one fragment, with no gaps regardless of how the triangles share edges. This makes conservative rasterization an effective way to guarantee watertight coverage for techniques that merge the fragments of adjacent triangles, such as the voxelization of a closed surface or the generation of a visibility buffer keyed by coverage.
The property depends on the inflation being at least large enough to cover half a pixel diagonal, because a pixel corner can be touched by a triangle whose centre is nearly a full diagonal away. Half the diagonal of a unit square is $\sqrt{2}/2 \approx 0.707$ pixels, which is why the published margin is stated in terms of the pixel diagonal rather than the pixel width. An implementation that inflates by exactly half a pixel leaves the corner case uncovered, and the resulting holes appear exactly at the pathological corners where two triangles meet at an acute angle.
The second dependency is the subpixel grid. Inflation in fixed-point units must be rounded up, not to nearest, or the guaranteed margin shrinks by up to half a subpixel unit. With 8 subpixel bits, rounding down by one unit is $1/256$ of a pixel, which is negligible for a one-pixel margin but not for a margin tuned tightly to the diagonal. Implementations generally compute the shift conservatively and accept the extra fraction.
Where it interacts with clipping and depth
Clipping in the homogeneous stage happens before rasterization and is unaware of the conservative mode. A triangle clipped at the viewport edge produces new vertices exactly on the clip plane, and its inflated form extends beyond the viewport by the inflation margin; the bounding box and scissor clamp that away, so no fragment is generated outside the target. The important case is a triangle that is entirely outside the viewport but within the inflation distance of the edge: conservative rasterization would legitimately cover a pixel on the border, and the clipper removes the triangle before that can happen. Clipping must therefore be disabled or replaced by a scissor when conservative coverage of border pixels matters, which is a known interaction for shadow volume rendering.
Depth behaves differently as well. A conservative fragment’s depth must be the depth of the point on the triangle nearest to the pixel, not the depth extrapolated to the pixel centre, because the centre may lie outside the triangle and the extrapolated depth may be in front of or behind the true surface. Published formulations use the depth at the closest point of the triangle to the pixel, or accept the extrapolated depth where the guarantee only concerns presence. For voxelization this is irrelevant; for a conservative depth prepass it matters, and the usual advice is not to mix the two.
Measuring the over-coverage
The fraction of extra fragments depends on the triangle’s shape and size. For a large triangle, the boundary adds a fringe of about one pixel around the perimeter, so the relative overhead scales as the perimeter divided by the area; for a triangle hundreds of pixels across, the overhead is a fraction of a percent. For small triangles, the overhead dominates: a triangle smaller than a pixel is inflated to cover several pixels, and the number of fragments can exceed the number of pixels the triangle has any claim to by a large factor. Tessellated meshes with sub-pixel triangles therefore pay the most, which is the opposite of the usual intuition that small primitives are cheap.
The overhead is also visible as a bias in any downstream statistic. An occlusion query counting conservative fragments overestimates the covered area; a voxelization records voxels the surface touches but does not enter, which is the intended behaviour but changes the definition of occupancy. Any algorithm feeding conservative fragments into a measurement must be clear about whether it wants touching or containing.
The counterpart to this article is the sampling approach described in multisampling, which addresses a different deficiency of the same point test. MSAA asks whether any of several points is inside and uses the answer to soften an edge; conservative rasterization asks whether any point of the pixel is inside and uses the answer to guarantee presence. Both replace the single centre test, and neither is a superset of the other: MSAA can still miss a triangle that grazes a pixel corner without hitting a sample, and conservative rasterization produces no fractional coverage at all.
References
- Conservative Rasterization — Akenine-Möller & Aila, GPU Gems 2, Chapter 42
- Conservative Rasterization — Hasselgren, Akenine-Möller & Ohlsson, Eurographics Symposium on Rendering 2005
- Direct3D 12 Conservative Rasterization — Microsoft