This has been around for a long while, so there should be plenty of good info out there on it.
Just to briefly back up and clarify: There are basically two different types of “early depth test”. The first is performed per-fragment as you’d expect at the resolution of the depth buffer. Call this “fine-grained Z” or “early Z”. It just performs the usual depth test before the fragment shader for a fragment has executed, because it knows the fragment shader won’t change the depth value (in the typical case).
Then even further back in the pipeline there’s the “early depth test” that discards whole primitives (or whole pixel tiles covered by part of primitives). Call this “course-grained Z”. This makes use of a “conservative depth” buffer stored at a lower resolution than per-pixel (or per-sample), possibly with multiple hierarchical levels. 10+ years ago, NVidia called their scheme ZCULL and ATI/AMD called theirs Hi-Z (aka Hierarchical Z), IIRC. Basically, this course-grained Z buffer stores the “worst case” depth for a multi-pixel region. The pipeline then compares the “worst case” depth across the primitive to values in this buffer. If the comparison says that even in the worst case, no fragments from the primitive will make it to the framebuffer, then the pipeline can kill off the whole pixel tile. That might cover the whole primitive, in which case the whole primitive is rejected.
Here are a few links:
- GPU Programming Guide - GeForce 8 and 9 Series (12/2008; NVIDIA) - Search for ZCULL
- Using Vertex Buffer Objects Well (9/2008; NVIDIA) - Search for ZCULL
- Depth in-depth (2007; AMD) - Search for Hierarchical Z
- Applications of Explicit Early-Z Culling (8/2004; ATI) - Search for Hierarchical Z