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Β§
- Bucket
Range π - A horizontal range in depth-bucket coordinates.
- Depth
Buffer π - Depth
State π - Coarse state for the depth buffer.
EnumsΒ§
- Depth
Segment π
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.