TGSI

TGSI, Tungsten Graphics Shader Infrastructure, is an intermediate language for describing shaders. Since Gallium is inherently shaderful, shaders are an important part of the API. TGSI is the only intermediate representation used by all drivers.

Basics

All TGSI instructions, known as opcodes, operate on arbitrary-precision floating-point four-component vectors. An opcode may have up to one destination register, known as dst, and between zero and three source registers, called src0 through src2, or simply src if there is only one.

Some instructions, like I2F, permit re-interpretation of vector components as integers. Other instructions permit using registers as two-component vectors with double precision; see Double ISA.

When an instruction has a scalar result, the result is usually copied into each of the components of dst. When this happens, the result is said to be replicated to dst. RCP is one such instruction.

Source Modifiers

TGSI supports 32-bit negate and absolute value modifiers on floating-point inputs, and 32-bit integer negates on some drivers. The negate applies after absolute value if both are present.

The type of an input can be found by tgsi_opcode_infer_src_type(), and TGSI_OPCODE_MOV and the second and third operands of TGSI_OPCODE_UCMP (which return TGSI_TYPE_UNTYPED) are also considered floats for the purpose of source modifiers.

Other Modifiers

The saturate modifier clamps 32-bit destination stores to [0.0, 1.0].

For arithmetic instruction having a precise modifier certain optimizations which may alter the result are disallowed. Example: add(mul(a,b),c) can’t be optimized to TGSI_OPCODE_MAD, because some hardware only supports the fused MAD instruction.

Instruction Set

Core ISA

These opcodes are guaranteed to be available regardless of the driver being used.

ARL (Address Register Load)
\[ \begin{align}\begin{aligned}dst.x = (int) \lfloor src.x\rfloor\\dst.y = (int) \lfloor src.y\rfloor\\dst.z = (int) \lfloor src.z\rfloor\\dst.w = (int) \lfloor src.w\rfloor\end{aligned}\end{align} \]
MOV (Move)
\[ \begin{align}\begin{aligned}dst.x = src.x\\dst.y = src.y\\dst.z = src.z\\dst.w = src.w\end{aligned}\end{align} \]
RCP (Reciprocal)

This instruction replicates its result.

\[dst = \frac{1}{src.x}\]
RSQ (Reciprocal Square Root)

This instruction replicates its result. The results are undefined for src <= 0.

\[dst = \frac{1}{\sqrt{src.x}}\]
SQRT (Square Root)

This instruction replicates its result. The results are undefined for src < 0.

\[dst = {\sqrt{src.x}}\]
MUL (Multiply)
\[ \begin{align}\begin{aligned}dst.x = src0.x \times src1.x\\dst.y = src0.y \times src1.y\\dst.z = src0.z \times src1.z\\dst.w = src0.w \times src1.w\end{aligned}\end{align} \]
ADD (Add)
\[ \begin{align}\begin{aligned}dst.x = src0.x + src1.x\\dst.y = src0.y + src1.y\\dst.z = src0.z + src1.z\\dst.w = src0.w + src1.w\end{aligned}\end{align} \]
DP3 (3-component Dot Product)

This instruction replicates its result.

\[\begin{split}\begin{aligned} dst = & src0.x \times src1.x +\\ & src0.y \times src1.y +\\ & src0.z \times src1.z \end{aligned}\end{split}\]
DP4 (4-component Dot Product)

This instruction replicates its result.

\[\begin{split}\begin{aligned} dst = & src0.x \times src1.x +\\ & src0.y \times src1.y +\\ & src0.z \times src1.z +\\ & src0.w \times src1.w \end{aligned}\end{split}\]
MIN (Minimum)
\[ \begin{align}\begin{aligned}dst.x = min(src0.x, src1.x)\\dst.y = min(src0.y, src1.y)\\dst.z = min(src0.z, src1.z)\\dst.w = min(src0.w, src1.w)\end{aligned}\end{align} \]
MAX (Maximum)
\[ \begin{align}\begin{aligned}dst.x = max(src0.x, src1.x)\\dst.y = max(src0.y, src1.y)\\dst.z = max(src0.z, src1.z)\\dst.w = max(src0.w, src1.w)\end{aligned}\end{align} \]
SLT (Set On Less Than)
\[ \begin{align}\begin{aligned}dst.x = (src0.x < src1.x) ? 1.0F : 0.0F\\dst.y = (src0.y < src1.y) ? 1.0F : 0.0F\\dst.z = (src0.z < src1.z) ? 1.0F : 0.0F\\dst.w = (src0.w < src1.w) ? 1.0F : 0.0F\end{aligned}\end{align} \]
SGE (Set On Greater Equal Than)
\[ \begin{align}\begin{aligned}dst.x = (src0.x >= src1.x) ? 1.0F : 0.0F\\dst.y = (src0.y >= src1.y) ? 1.0F : 0.0F\\dst.z = (src0.z >= src1.z) ? 1.0F : 0.0F\\dst.w = (src0.w >= src1.w) ? 1.0F : 0.0F\end{aligned}\end{align} \]
MAD (Multiply And Add)

Perform a * b + c. The implementation is free to decide whether there is an intermediate rounding step or not.

\[ \begin{align}\begin{aligned}dst.x = src0.x \times src1.x + src2.x\\dst.y = src0.y \times src1.y + src2.y\\dst.z = src0.z \times src1.z + src2.z\\dst.w = src0.w \times src1.w + src2.w\end{aligned}\end{align} \]
LRP (Linear Interpolate)
\[ \begin{align}\begin{aligned}dst.x = src0.x \times src1.x + (1 - src0.x) \times src2.x\\dst.y = src0.y \times src1.y + (1 - src0.y) \times src2.y\\dst.z = src0.z \times src1.z + (1 - src0.z) \times src2.z\\dst.w = src0.w \times src1.w + (1 - src0.w) \times src2.w\end{aligned}\end{align} \]
FMA (Fused Multiply-Add)

Perform a * b + c with no intermediate rounding step.

\[ \begin{align}\begin{aligned}dst.x = src0.x \times src1.x + src2.x\\dst.y = src0.y \times src1.y + src2.y\\dst.z = src0.z \times src1.z + src2.z\\dst.w = src0.w \times src1.w + src2.w\end{aligned}\end{align} \]
FRC (Fraction)
\[ \begin{align}\begin{aligned}dst.x = src.x - \lfloor src.x\rfloor\\dst.y = src.y - \lfloor src.y\rfloor\\dst.z = src.z - \lfloor src.z\rfloor\\dst.w = src.w - \lfloor src.w\rfloor\end{aligned}\end{align} \]
FLR (Floor)
\[ \begin{align}\begin{aligned}dst.x = \lfloor src.x\rfloor\\dst.y = \lfloor src.y\rfloor\\dst.z = \lfloor src.z\rfloor\\dst.w = \lfloor src.w\rfloor\end{aligned}\end{align} \]
ROUND (Round)
\[ \begin{align}\begin{aligned}dst.x = round(src.x)\\dst.y = round(src.y)\\dst.z = round(src.z)\\dst.w = round(src.w)\end{aligned}\end{align} \]
EX2 (Exponential Base 2)

This instruction replicates its result.

\[dst = 2^{src.x}\]
LG2 (Logarithm Base 2)

This instruction replicates its result.

\[dst = \log_2{src.x}\]
POW (Power)

This instruction replicates its result.

\[dst = src0.x^{src1.x}\]
LDEXP (Multiply Number by Integral Power of 2)

src1 is an integer.

\[ \begin{align}\begin{aligned}dst.x = src0.x * 2^{src1.x}\\dst.y = src0.y * 2^{src1.y}\\dst.z = src0.z * 2^{src1.z}\\dst.w = src0.w * 2^{src1.w}\end{aligned}\end{align} \]
COS (Cosine)

This instruction replicates its result.

\[dst = \cos{src.x}\]
DDX, DDX_FINE (Derivative Relative To X)

The fine variant is only used when pipe_caps.fs_fine_derivative is advertised. When it is, the fine version guarantees one derivative per row while DDX is allowed to be the same for the entire 2x2 quad.

\[ \begin{align}\begin{aligned}dst.x = partialx(src.x)\\dst.y = partialx(src.y)\\dst.z = partialx(src.z)\\dst.w = partialx(src.w)\end{aligned}\end{align} \]
DDY, DDY_FINE (Derivative Relative To Y)

The fine variant is only used when pipe_caps.fs_fine_derivative is advertised. When it is, the fine version guarantees one derivative per column while DDY is allowed to be the same for the entire 2x2 quad.

\[ \begin{align}\begin{aligned}dst.x = partialy(src.x)\\dst.y = partialy(src.y)\\dst.z = partialy(src.z)\\dst.w = partialy(src.w)\end{aligned}\end{align} \]
PK2H (Pack Two 16-bit Floats)

This instruction replicates its result.

\[\begin{split}\begin{aligned} dst = & f32\_to\_f16(src.x) | \\ ( & f32\_to\_f16(src.y) \ll 16) \end{aligned}\end{split}\]
SEQ (Set On Equal)
\[ \begin{align}\begin{aligned}dst.x = (src0.x == src1.x) ? 1.0F : 0.0F\\dst.y = (src0.y == src1.y) ? 1.0F : 0.0F\\dst.z = (src0.z == src1.z) ? 1.0F : 0.0F\\dst.w = (src0.w == src1.w) ? 1.0F : 0.0F\end{aligned}\end{align} \]
SGT (Set On Greater Than)
\[ \begin{align}\begin{aligned}dst.x = (src0.x > src1.x) ? 1.0F : 0.0F\\dst.y = (src0.y > src1.y) ? 1.0F : 0.0F\\dst.z = (src0.z > src1.z) ? 1.0F : 0.0F\\dst.w = (src0.w > src1.w) ? 1.0F : 0.0F\end{aligned}\end{align} \]
SIN (Sine)

This instruction replicates its result.

\[dst = \sin{src.x}\]
SLE (Set On Less Equal Than)
\[ \begin{align}\begin{aligned}dst.x = (src0.x <= src1.x) ? 1.0F : 0.0F\\dst.y = (src0.y <= src1.y) ? 1.0F : 0.0F\\dst.z = (src0.z <= src1.z) ? 1.0F : 0.0F\\dst.w = (src0.w <= src1.w) ? 1.0F : 0.0F\end{aligned}\end{align} \]
SNE (Set On Not Equal)
\[ \begin{align}\begin{aligned}dst.x = (src0.x != src1.x) ? 1.0F : 0.0F\\dst.y = (src0.y != src1.y) ? 1.0F : 0.0F\\dst.z = (src0.z != src1.z) ? 1.0F : 0.0F\\dst.w = (src0.w != src1.w) ? 1.0F : 0.0F\end{aligned}\end{align} \]
TEX (Texture Lookup)

for array textures src0.y contains the slice for 1D, and src0.z contain the slice for 2D.

for shadow textures with no arrays (and not cube map), src0.z contains the reference value.

for shadow textures with arrays, src0.z contains the reference value for 1D arrays, and src0.w contains the reference value for 2D arrays and cube maps.

for cube map array shadow textures, the reference value cannot be passed in src0.w, and TEX2 must be used instead.

\[ \begin{align}\begin{aligned}coord = src0\\shadow\_ref = src0.z \textrm{ or } src0.w \textrm{ (optional)}\\unit = src1\\dst = texture\_sample(unit, coord, shadow\_ref)\end{aligned}\end{align} \]
TEX2 (Texture Lookup (for shadow cube map arrays only))

this is the same as TEX, but uses another reg to encode the reference value.

\[ \begin{align}\begin{aligned}coord = src0\\shadow\_ref = src1.x\\unit = src2\\dst = texture\_sample(unit, coord, shadow\_ref)\end{aligned}\end{align} \]
TXD (Texture Lookup with Derivatives)
\[ \begin{align}\begin{aligned}coord = src0\\ddx = src1\\ddy = src2\\unit = src3\\dst = texture\_sample\_deriv(unit, coord, ddx, ddy)\end{aligned}\end{align} \]
TXP (Projective Texture Lookup)
\[ \begin{align}\begin{aligned}coord.x = src0.x / src0.w\\coord.y = src0.y / src0.w\\coord.z = src0.z / src0.w\\coord.w = src0.w\\unit = src1\\dst = texture\_sample(unit, coord)\end{aligned}\end{align} \]
UP2H (Unpack Two 16-Bit Floats)
\[ \begin{align}\begin{aligned}dst.x = f16\_to\_f32(src0.x \& 0xffff)\\dst.y = f16\_to\_f32(src0.x \gg 16)\\dst.z = f16\_to\_f32(src0.x \& 0xffff)\\dst.w = f16\_to\_f32(src0.x \gg 16)\end{aligned}\end{align} \]
Note

Considered for removal.

UP2US (Unpack Two Unsigned 16-Bit Scalars)

TBD

Note

Considered for removal.

UP4B (Unpack Four Signed 8-Bit Values)

TBD

Note

Considered for removal.

UP4UB (Unpack Four Unsigned 8-Bit Scalars)

TBD

Note

Considered for removal.

ARR (Address Register Load With Round)
\[ \begin{align}\begin{aligned}dst.x = (int) round(src.x)\\dst.y = (int) round(src.y)\\dst.z = (int) round(src.z)\\dst.w = (int) round(src.w)\end{aligned}\end{align} \]
SSG (Set Sign)
\[ \begin{align}\begin{aligned}dst.x = (src.x > 0) ? 1 : (src.x < 0) ? -1 : 0\\dst.y = (src.y > 0) ? 1 : (src.y < 0) ? -1 : 0\\dst.z = (src.z > 0) ? 1 : (src.z < 0) ? -1 : 0\\dst.w = (src.w > 0) ? 1 : (src.w < 0) ? -1 : 0\end{aligned}\end{align} \]
CMP (Compare)
\[ \begin{align}\begin{aligned}dst.x = (src0.x < 0) ? src1.x : src2.x\\dst.y = (src0.y < 0) ? src1.y : src2.y\\dst.z = (src0.z < 0) ? src1.z : src2.z\\dst.w = (src0.w < 0) ? src1.w : src2.w\end{aligned}\end{align} \]
KILL_IF (Conditional Discard)

Conditional discard. Allowed in fragment shaders only.

Pseudocode:

if (src.x < 0 || src.y < 0 || src.z < 0 || src.w < 0)
   discard
endif
KILL (Discard)

Unconditional discard. Allowed in fragment shaders only.

DEMOTE (Demote Invocation to a Helper)

This demotes the current invocation to a helper, but continues execution (while KILL may or may not terminate the invocation). After this runs, all the usual helper invocation rules apply about discarding buffer and render target writes. This is useful for having accurate derivatives in the other invocations which have not been demoted.

Allowed in fragment shaders only.

TXB (Texture Lookup With Bias)

for cube map array textures and shadow cube maps, the bias value cannot be passed in src0.w, and TXB2 must be used instead.

if the target is a shadow texture, the reference value is always in src.z (this prevents shadow 3d and shadow 2d arrays from using this instruction, but this is not needed).

\[ \begin{align}\begin{aligned}coord.x = src0.x\\coord.y = src0.y\\coord.z = src0.z\\coord.w = none\\bias = src0.w\\unit = src1\\dst = texture\_sample(unit, coord, bias)\end{aligned}\end{align} \]
TXB2 (Texture Lookup With Bias (some cube maps only))

this is the same as TXB, but uses another reg to encode the LOD bias value for cube map arrays and shadow cube maps. Presumably shadow 2d arrays and shadow 3d targets could use this encoding too, but this is not legal.

if the target is a shadow cube map array, the reference value is in src1.y.

\[ \begin{align}\begin{aligned}coord = src0\\bias = src1.x\\unit = src2\\dst = texture\_sample(unit, coord, bias)\end{aligned}\end{align} \]
DIV (Divide)
\[ \begin{align}\begin{aligned}dst.x = \frac{src0.x}{src1.x}\\dst.y = \frac{src0.y}{src1.y}\\dst.z = \frac{src0.z}{src1.z}\\dst.w = \frac{src0.w}{src1.w}\end{aligned}\end{align} \]
DP2 (2-component Dot Product)

This instruction replicates its result.

\[\begin{split}\begin{aligned} dst = & src0.x \times src1.x + \\ & src0.y \times src1.y \end{aligned}\end{split}\]
TXL (Texture Lookup With explicit LOD)

for cube map array textures, the explicit LOD value cannot be passed in src0.w, and TXL2 must be used instead.

if the target is a shadow texture, the reference value is always in src.z (this prevents shadow 3d / 2d array / cube targets from using this instruction, but this is not needed).

\[ \begin{align}\begin{aligned}coord.x = src0.x\\coord.y = src0.y\\coord.z = src0.z\\coord.w = none\\lod = src0.w\\unit = src1\\dst = texture\_sample(unit, coord, lod)\end{aligned}\end{align} \]
TXL2 (Texture Lookup With explicit LOD (for cube map arrays only))

this is the same as TXL, but uses another reg to encode the explicit LOD value. Presumably shadow 3d / 2d array / cube targets could use this encoding too, but this is not legal.

if the target is a shadow cube map array, the reference value is in src1.y.

\[ \begin{align}\begin{aligned}coord = src0\\lod = src1.x\\unit = src2\\dst = texture\_sample(unit, coord, lod)\end{aligned}\end{align} \]

Compute ISA

These opcodes are primarily provided for special-use computational shaders. Support for these opcodes indicated by a special pipe capability bit (TBD).

XXX doesn’t look like most of the opcodes really belong here.

CEIL (Ceiling)
\[ \begin{align}\begin{aligned}dst.x = \lceil src.x\rceil\\dst.y = \lceil src.y\rceil\\dst.z = \lceil src.z\rceil\\dst.w = \lceil src.w\rceil\end{aligned}\end{align} \]
TRUNC (Truncate)
\[ \begin{align}\begin{aligned}dst.x = trunc(src.x)\\dst.y = trunc(src.y)\\dst.z = trunc(src.z)\\dst.w = trunc(src.w)\end{aligned}\end{align} \]
MOD (Modulus)
\[ \begin{align}\begin{aligned}dst.x = src0.x \bmod src1.x\\dst.y = src0.y \bmod src1.y\\dst.z = src0.z \bmod src1.z\\dst.w = src0.w \bmod src1.w\end{aligned}\end{align} \]
UARL (Integer Address Register Load)

Moves the contents of the source register, assumed to be an integer, into the destination register, which is assumed to be an address (ADDR) register.

TXF (Texel Fetch)

As per GL_NV_gpu_program4, extract a single texel from a specified texture image or PIPE_BUFFER resource. The source sampler may not be a CUBE or SHADOW. src0 is a four-component signed integer vector used to identify the single texel accessed. 3 components + level. If the texture is multisampled, then the fourth component indicates the sample, not the mipmap level. Just like texture instructions, an optional offset vector is provided, which is subject to various driver restrictions (regarding range, source of offsets). This instruction ignores the sampler state.

TXF(uint_vec coord, int_vec offset).

TXQ (Texture Size Query)

As per GL_NV_gpu_program4, retrieve the dimensions of the texture depending on the target. For 1D (width), 2D/RECT/CUBE (width, height), 3D (width, height, depth), 1D array (width, layers), 2D array (width, height, layers). Also return the number of accessible levels (last_level - first_level + 1) in W.

For components which don’t return a resource dimension, their value is undefined.

\[ \begin{align}\begin{aligned}lod = src0.x\\dst.x = texture\_width(unit, lod)\\dst.y = texture\_height(unit, lod)\\dst.z = texture\_depth(unit, lod)\\dst.w = texture\_levels(unit)\end{aligned}\end{align} \]
TXQS (Texture Samples Query)

This retrieves the number of samples in the texture, and stores it into the x component as an unsigned integer. The other components are undefined. If the texture is not multisampled, this function returns (1, undef, undef, undef).

\[dst.x = texture\_samples(unit)\]
TG4 (Texture Gather)

As per GL_ARB_texture_gather, gathers the four texels to be used in a bi-linear filtering operation and packs them into a single register. Only works with 2D, 2D array, cubemaps, and cubemaps arrays. For 2D textures, only the addressing modes of the sampler and the top level of any mip pyramid are used. Set W to zero. It behaves like the TEX instruction, but a filtered sample is not generated. The four samples that contribute to filtering are placed into XYZW in clockwise order, starting with the (u,v) texture coordinate delta at the following locations (-, +), (+, +), (+, -), (-, -), where the magnitude of the deltas are half a texel.

pipe_caps.texture_sm5 enhances this instruction to support shadow per-sample depth compares, single component selection, and a non-constant offset. It doesn’t allow support for the GL independent offset to get i0,j0. This would require another CAP is HW can do it natively. For now we lower that before TGSI.

pipe_caps.tgsi_tg4_component_in_swizzle changes the encoding so that component is stored in the sampler source swizzle x.

(without TGSI_TG4_COMPONENT_IN_SWIZZLE)

\[ \begin{align}\begin{aligned}coord = src0\\component = src1\\dst = texture\_gather4 (unit, coord, component)\end{aligned}\end{align} \]

(with TGSI_TG4_COMPONENT_IN_SWIZZLE)

\[ \begin{align}\begin{aligned}coord = src0\\dst = texture\_gather4 (unit, coord)\\\text{component is encoded in sampler swizzle.}\end{aligned}\end{align} \]

(with SM5 - cube array shadow)

\[ \begin{align}\begin{aligned}coord = src0\\compare = src1\\dst = texture\_gather (uint, coord, compare)\end{aligned}\end{align} \]
LODQ (level of detail query)

Compute the LOD information that the texture pipe would use to access the texture. The Y component contains the computed LOD lambda_prime. The X component contains the LOD that will be accessed, based on min/max LODs and mipmap filters.

\[ \begin{align}\begin{aligned}coord = src0\\dst.xy = lodq(uint, coord);\end{aligned}\end{align} \]
CLOCK (retrieve the current shader time)

Invoking this instruction multiple times in the same shader should cause monotonically increasing values to be returned. The values are implicitly 64-bit, so if fewer than 64 bits of precision are available, to provide expected wraparound semantics, the value should be shifted up so that the most significant bit of the time is the most significant bit of the 64-bit value.

\[dst.xy = clock()\]

Integer ISA

These opcodes are used for integer operations. Support for these opcodes indicated by pipe_shader_caps.integers (all of them?)

I2F (Signed Integer To Float)

Rounding is unspecified (round to nearest even suggested).

\[ \begin{align}\begin{aligned}dst.x = (float) src.x\\dst.y = (float) src.y\\dst.z = (float) src.z\\dst.w = (float) src.w\end{aligned}\end{align} \]
U2F (Unsigned Integer To Float)