To continue the series on Flash 11 Stage3D shader programming, this week we’ll take a look at the data types your shader has available and finally dive into some actual AGAL assembly syntax.

To begin, let’s look at the different types of data a shader program—vertex and fragment—deals with:

Type Number Available Name Origin Accessible From Purpose
Vertex Temporary 8 vt0 – vt7 Vertex shader code Vertex shader Temporary variables for vertex shader computations
Fragment Temporary 8 ft0 – ft7 Fragment shader code Fragment shader Temporary variables for fragment shader computations
Vertex Attribute 8 va0 – va7 Context3D.setVertexBufferAt Vertex shader Vertex-specific data (e.g. texture coordinates, color)
Vertex Constant 128 vc0 – vc1 Context3D.setProgramConstants Vertex shader Constants across the whole Context3D.drawTriangles call for vertex shader use
Fragment Constant 28 fc0 – fc27 Context3D.setProgramConstants Fragment shader Constants across the whole Context3D.drawTriangles call for fragment shader use
Fragment Sampler 8 fs0 – fs7 Context3D.setTextureAt Fragment shader Textures for fragment shader use
Varying 8 v0 – v7 Vertex shader code Vertex and Fragment shader Passing data from vertex shader to fragment shader with automatic interpolation
Output Position 1 op Vertex shader code Vertex shader Output of the vertex shader
Output Color 1 oc Fragment shader code Fragment shader Output of the fragment shader

Together, these data types are your tools to, ultimately, draw the pixels (other than the background color) that make up your 3D scene. It’s therefore very important to master each of these data types so that you can put them to full use. Before we jump into the actual AGAL assembly syntax, let’s discuss what these data types are in the first place. With the exception of fragment samplers, all of them actually a collection of four floating point numbers. This is quite different to most CPU programming in that the “basic unit” is not a byte but instead four floats. You are, however, allowed to specifically read from and write to the data’s components. You do that through a familiar dot syntax:

vt0.x
vt0.y
vt0.z
vt0.w

These are simple ways of accessing the components, but you can also access two, three, or four of the components at a time:

vt0.xy
vt0.xyz
vt0.xyzw

You can even “swizzle” around the components so the result is out of order:

vt0.yx
vt0.zyx
vt0.wzyx
vt0.xzwy

And you can even duplicate values:

vt0.xx
vt0.xxx
vt0.xxxx
vt0.xyyx
vt0.zzzy

This is all very flexible and allows you to really make the most out of the data your shaders deal with. Now, let’s take a look at some basic AGAL assembly syntax:

mov ft0, va0

Each line of the shader program contains one instruction, which performs exactly the one operation listed. To show the anatomy of this instruction, I’ll annotate it:

Instruction | Argument 1 | Argument 2
mov         | ft0,       | va0

This code simply copies the data stored in the first vertex attribute (va0) to the first vertex shader temporary (ft0). It is not actually “moved” in the same sense as when you move files around on a file system: the origin (va0) is unchanged after this instruction.

Most of the instructions take three arguments though:

add vt0, vt1, vt2

This code adds vt1 and vt2 together and puts the output in vt0. You should be seeing a pattern here: the result of the operation is (except with the kil instruction) the first argument an the operands are the remaining arguments. Let’s see how this looks when we mix in some components and swizzling:

add vt0.x, vt1.x, vt2.x
add vt0.xy, vt1.zw, vt2.yy
add vt0.xyz, vt1.yzw, vt2.zzz
add vt0, vt1.zyxw, vt2.yzwy

You’ll want to make sure you’re matching the same number of components across the board and that each of the components of the operands have been written to (by you or by Flash) before you read from them. Now, let’s look at the funkiest instructions starting with kil:

kil ft0.x

The kil instruction is only available in fragment shaders and it only takes one argument, which must be a simple component. If the component is less than zero, the fragment shader is immediately halted and no fragment/pixel is generated/drawn. Another set of weird instructions represent the only conditional logic we have in AGAL. Each sets a value only on a condition: sge (“set if greater or equal”) and slt (“set if less than”). If the check value doesn’t match the condition then zero is written instead. Here’s how they look: (with annotation)

Instruction | Destination | Check Value | Value to set
sge         | ft0,        | ft1.x,      | ft2
slt         | ft0,        | ft1.x       | ft2

In order to use these, you’ll need to get tricky. For example, you can exploit some simple mathematical facts since the result if the check doesn’t pass is zero. Consider multiplying or adding the result. If you multiply by zero you’ll get zero and if you add zero you’ll get the same value. Obviously the exact logic will be up to your own fragment shader, but if you work hard you can come up with some simple conditional logic by exploiting these instructions.

Now we come to a crucial instruction that just so happens to be the weirdest one out there:

tex ft0, v0, fs0 <2d, linear, nomip>

The all-important tex instruction samples a texture (bound to a fragment sampler) at a given texture coordinate and returns an RGBA color value. The wacky part is that you must specify how you want to sample the texture by using flags in angle brackets after the arguments. These are the allowed values:

  • Texture Type

    • 2d (normal 2D textures)
    • cube (cube maps)
  • Filtering Method

  • MIP-Mapping

    • mipnone/nomip (no MIP-mapping)
    • mipnearest (nearest MIP map only)
    • miplinear (blend between two nearest MIP maps)
  • Texture Repeat

    • clamp (clamp texture coordinates to [0:1])
    • wrap (wrap texture coordinates by ignoring the integer part)
    • repeat (texture coordinates outside [0:1] are the border color)

Stay tuned for next time when we’ll actually get a shader program up and running! Until then, if you’ve spotted a bug or have a suggestion, leave a comment!