Skip to main content

Module depth

Module depth 

Source
Expand description

CPU-based depth buffers.

GPUs have depth buffers, so why not use them for CPU rendering as well! For many of the existing CPU-based 2D renderers, this is not really possible because they use immediate-mode rendering. But Vello CPU first converts all rendering commands into strips and then processes them, meaning that before we even start with rasterization, we already have a rough idea of what we are about to rasterize. Therefore, we can use this information to go about performing rasterization in a smarter way.

Unlike GPUs, it is not feasible to have a per-pixel depth buffer. While certain per-pixel work can be expensive (images, gradients), what is even more expensive is splitting up work in a too granular fashion, especially when only dealing with solid colors. It is much faster to just fill a 256x1 buffer of pixels with a single colors than doing it in 32 chunks of 4x1, just to save 50% pixel work.

Therefore, the CPU-based depth buffer acts at a much coarser granularity. Vertically, it comes very natural to simply decide that one depth buffer entry covers a range of Tile::HEIGHT pixels, since all commands are executed at this height anyway. Choosing a width is much trickier: Similarly, the width should be a multiple of Tile::WIDTH, but using this as the granularity is still to narrow. After some empirical measurements, it was decided that a width of DEPTH_BUCKET_WIDTH overall represents a good compromise across different paint types.

How this essentially works now is that, once we’ve collected all strips, we split them up into opaque fills aligned to the depth bucket width, and all other fills which either have transparency or stem from non-aligned parts of an opaque fill. During rasterization, we first render the opaque strips front-to-back, each time checking the depth buffer whether this hasn’t already been filled by an opaque strip with a higher z-index. Otherwise, we perform the fill and update the depth buffer.

Then, we simply render the remaining strips back to front, again always comparing the depth against what’s written in the depth buffer and skipping any commands that would be fully covered by existing content.

StructsΒ§

BucketRange πŸ”’
A horizontal range in depth-bucket coordinates.
DepthBuffer πŸ”’
DepthState πŸ”’
Coarse state for the depth buffer.

EnumsΒ§

DepthSegment πŸ”’

ConstantsΒ§

DEPTH_BUCKET_TILE_WIDTH πŸ”’
DEPTH_BUCKET_WIDTH πŸ”’

FunctionsΒ§

bucket_span πŸ”’
split_opaque_span πŸ”’
Splits a tile-aligned span into regular edge spans and a depth-trackable opaque middle span.