What Is WaveActiveBallot in DirectX HLSL?
WaveActiveBallot is an intrinsic function in High-Level
Shader Language (HLSL) introduced with Shader Model 6.0 that allows
threads within a single GPU wave (or warp) to communicate without using
shared memory. This article explains the fundamentals of
WaveActiveBallot, how it constructs a bitmask
representation of boolean conditions across active lanes in a SIMD wave,
and how developers utilize it to optimize compute workloads and
eliminate thread divergence.
Understanding Wave-Level Execution
Modern GPUs execute groups of parallel threads synchronously in units known as waves (DirectX terminology), warps (NVIDIA), or wavefronts (AMD). Typically consisting of 32 or 64 lanes, every lane in a wave runs the same instruction concurrently.
Before wave intrinsics were supported, individual lanes operated
largely in isolation unless they synchronized through threadgroup shared
memory (groupshared) or global memory using atomic
operations. WaveActiveBallot circumvents this overhead by
performing hardware-level lane communication directly across the SIMD
vector registers.
How WaveActiveBallot Queries Boolean States
The signature of the function is defined as:
uint4 WaveActiveBallot(bool expr);
When called, each active lane in the wave evaluates its local boolean
expression (expr). The GPU hardware collects these boolean
results and consolidates them into a 128-bit bitmask distributed across
a four-component vector of 32-bit unsigned integers
(uint4).
The mapping between lane index and bit position is deterministic:
- Lane Index to Bit Mapping: Lane
Ncorresponds to bit(N % 32)within componentN / 32. - Component Allocation:
- Component
xstores results for lanes 0 through 31. - Component
ystores results for lanes 32 through 63. - Component
zstores results for lanes 64 through 95. - Component
wstores results for lanes 96 through 127.
- Component
If lane N is active and evaluates expr to
true, bit N in the 128-bit vector is set to
1. If lane N is inactive (for example, due to
flow control or boundary conditions) or evaluates expr to
false, the corresponding bit is set to 0. The
identical 128-bit mask is returned to every active lane in that wave
simultaneously.
Practical Applications in Shaders
By providing an instantaneous snapshot of states across an entire
wave, WaveActiveBallot enables several performance
optimizations:
- Counting and Compaction: Combining
WaveActiveBallotwith the intrinsiccountbits()allows a wave to tally how many lanes meet a condition without issuing memory atomics. - First/Last Active Identification: Functions like
firstbitlow()can interrogate the ballot result to designate a single "leader" lane to perform expensive shared operations (such as a single atomic add to global memory on behalf of the whole wave). - Early Exits: Shaders can quickly evaluate whether zero, some, or all lanes require an expensive calculation, allowing the wave to skip costly code paths dynamically.