Register Masks, Swizzles, Negates and Indexing

 

By default, a register reference in a shader expands to a reference to all of the elements of the register, in x, y, z, w order. This means that whenever you write “R” where “R” is the name of some register, it automatically gets expanded (at least conceptually) to “R.xyzw”. What I want to get across is that the specific element-by-element reference to the register is made without you having to do anything. This is merely semantic convenience and efficiency.

 

What this means that it cost nothing extra to re-order or even ignore specific elements of a register if it makes sense to. I’ll say it again: it costs nothing to use these masks in your shaders. They are there so you can take advantage of the single-instruction/multiple-data nature of the shader language to possibly merge similar computations or save on register usage. If in fact you don’t need to have a value stored in ever element of a register, then by all means use a destination mask and only have the value you need written to the destination register.

 

destination mask/write mask

 

Note the word destination above. Masks can only be used to select which element of a register is to be written to. (Hence they are often referred to as write masks.) Even if an instruction usually writes to all four elements of the destination, the mask can be used to select which element(s) of the destination are written. If you leave an element out of a mask, it doesn’t get written. The element masks must be in order; x comes before y comes before z comes before w.

 

mov       r1,      c1 // use all

mov       r1.xyzw, c1 // use all explicitly (default)

mov       r1.xw,   c1 // just move c.x and c.w

mov       r1.wx,   c1 // Error! – invalid order

mov       r1.wzyx, c1 // Error! – invalid order

 

source swizzle

 

Note the word source above. Swizzles can only be used to select the order and the elements of a register to use as a source. A swizzle must specify four elements, though there is no restriction on the order. A swizzle consists of four letters, and each the letters must be one of “xyzw”.

 

mov       r1,  c1      // use all – same as below

mov       r1,  c1.xyzw // use all in order

mov       r1,  c1.wzyx // reverse the order

mov       r1,  c1.wwww // just use the w element

mov       r1,  c1.xyzy // replace w with y

mov       r1.w,  c1.zxyx // move c.x into r1.w

mov       r1.z,  c1.xzwy // move c.w into r1.z

mov       r1,  c1.x // error need 4, not 1

 

source negation

 

Negation can be used to negate an entire source register. They can be used with swizzles.

 

mov       r1,  c1   // move c1 into r1

mov       r1, -c1   // move negative c1 into r1

mov       r1.w, -r1 // negate just r1’s w & store it

mov       r1.w, -c1.zzzy // move –c1.y into r1.w

mov      -r1,  c1  // Error! Can’t negate destination

 

address registers

 

Not available in shader version 1.0. Only register a0.x can be used for version 1.1. The address register can be used as a signed offset into the constant register file and it can only be used in the mov instruction. The values in the address register when used must be compute to the legal range for the constant registers (i.e. 0 to 95 for most 1.1, 1.1 vertex shaders)

 

vs.1.1

mov       a0.x, c5.w // load a0.x

 

mov       r1, c1       // regular move, format 1

mov       r1, c[1]     // same thing alternate format

mov       r1, c[1+a0.x]// relative move