How subgroupBallotBitCount Counts Bits in GLSL
This article explains how the subgroupBallotBitCount
intrinsic function in GLSL evaluates a subgroup ballot to count active
invocations. It covers the structure of the uvec4 ballot
bitmask, the underlying population count operation executed across its
components, and how this differs from prefix-based ballot counting
functions.
Understanding the Subgroup Ballot Representation
In GLSL, subgroup ballot operations return a uvec4—a
vector of four 32-bit unsigned integers, providing up to 128 bits. Each
bit in this bitmask corresponds to a specific invocation within the
subgroup, ordered by gl_SubgroupInvocationID.
When an invocation evaluates a condition using
subgroupBallot(predicate), the hardware sets the bit
corresponding to that invocation's index to 1 if the
predicate is true and the invocation is active; otherwise,
it is set to 0. If a subgroup has fewer than 128
invocations, the unused higher-order bits are set to 0.
The Bit Counting Mechanism
The subgroupBallotBitCount(uvec4 value) function takes
an arbitrary ballot vector and returns the total number of set bits
(1s) contained within it. The counting process functions as
follows:
- Component-Wise Population Count: The hardware
executes a population count (
popcnt) operation on each 32-bit component of theuvec4vector (value.x,value.y,value.z, andvalue.w). The population count determines the number of non-zero bits within each individual 32-bit integer. - Summation: The counts from all four components are
summed together into a single scalar
uint.
Conceptually, the function evaluates to:
uint totalBits = bitCount(value.x) + bitCount(value.y) + bitCount(value.z) + bitCount(value.w);Most modern GPUs implement dedicated hardware instructions for population counting, allowing the GPU to determine the number of set bits per 32-bit word in one or very few clock cycles.
Scope and Behavior
- Global to the Ballot: Unlike
subgroupBallotInclusiveBitCountandsubgroupBallotExclusiveBitCount, which only sum bits up to the caller'sgl_SubgroupInvocationID,subgroupBallotBitCountcounts all active bits across the entire 128-bit mask regardless of which invocation calls it. - Uniform Result: If every invocation in a subgroup
passes the same
uvec4ballot tosubgroupBallotBitCount, every invocation receives the exact same return value. - Arbitrary Inputs: While commonly used on the result
of
subgroupBallot(), the function works on any validuvec4bitmask, functioning as a 128-bit population count utility.