|
|
The DirectX documentation places these in the input register section, but that is misleading since these registers must be initialized before they can be used, and since the results are lost between each shader invocation, they can't be used to pass any information between shader calls.
Twelve four-element vectors are available as temporary registers. Temporary registers are unique in that you can, unlike constant registers, use as many as you like as arguments for shader instructions. Temporary registers are considered uninitialized when a vertex shader starts, and an attempt to read from a temporary register before it is written to will cause the creation of a vertex shader to fail. This also means the temporary register memory is volatile—once the shader returns, whatever values were in the temporary registers are lost.
Address registers are designed to make it easy to index into the array of constant registers. The address registers allow you to provide a signed integer offset into the constant registers. These registers may be written to only by the mov instruction (mova in DirectX 9) and are write only; that is, they can be used only for indexing into the constant register array, and you can't use them any other way.
No address registers were available in VS 1.0 (DX8.0) vertex shaders, and only one address register element, a0.x, was made available in later versions. |
If you use the address register and the calculated offset is outside the legal range for a valid constant register, then the value returned will be a register of zeros. The address register can contain a signed integer offset. The calculated value in the register is stored as the largest floating point integer value that is not greater than the original value. This means that for positive values the fractional part is truncated, whereas for negative values the value is modified to the next larger integer value; that is, it rounds toward negative infinity.
The address register is initialized to 0, 0, 0, 0 when a shader in entered, but DirectX 8.1 shader assembler requires you to set the value in a0.x before using it. DirectX 9 does not force you to initialize the register before you use it. |
mov a0.x, c1.x // fails if vs.1.0, ok for vs.1.1 mov a0, c1 // error, only aO.x is OK mov a0.x, c1 // OK only aO.x is written mov a0.x, v0.x // OK mov a0.x, r0.x // OK mov a0.y, r0.x // fails if vs.1.0 or vs.1.1
You can use the address register by itself as an index or in conjunction with an offset. You cannot use it more than once or with another register. You can use it with a positive integer constant but only if they are being added; any negative sign will cause the compiler to give you a syntax error. However, the value that you mov into the address register can be negative.
mov r1 , c[a0.x] // as index mov r1 , c[5+a0.x] // as offset mov r1 , c[a0.x-5] // Error! Can't subtract mov r1 , c[-a0.x+5] // Error! Can't negate m4x4 oPos, v0, c[5+a0.x] // Can use even in macros
Finally, although not an instruction per se, it's useful to understand the pseudocode that you would use in the emulation of the address register assignment. Here's an example of how the mov instruction might be written in a simulator.
SetSourceRegisters(); // Simulate the mov a0.x, Source0.x instruction a0.x = (int) ::floor( Source0.x ); WriteDestinationRegisters( );
The loop counter is a scalar register that was added for control of 1 oop blocks. It's initialized from the parameters passed to the loop instruction and is a valid reference only inside a loop block—this includes inside a subroutine called from inside a loop block. The loop counter can be used for relative addressing of constants inside a loop block. |
The largest change with vertex shader 2.0 is the addition of flow control. This gives the ability for iterative vertex shaders, but also the potential to create slow shaders as well. If possible you should unroll any loops inside shaders if possible.
|
|